#TSV文字列: 桁区切り記号の追加

#TSV文字列: 桁区切り記号の追加

translate #TSV-String: Add Thousands Separators

指定の列範囲に桁区切り書式を適用します。START列からEND列の手前まで(ENDは含まない)に適用されます。インデックスは「0」から始まります。負のインデックスは末尾から逆算されます。STARTを省略した場合は「先頭から」、ENDを省略した場合は「末尾まで」となります。

Auto Step icon
Configs for this Auto Step
StrConfA
A: インプットTSV文字列をセットしてください *#{EL}
OptionConfB0
B0: 桁区切り記号を選択してください *
StrConfB1
B1: STARTインデックスをセットしてください(A列:”0″, C列:”2″, 末尾列:”-1″)#{EL}
StrConfB2
B2: ENDインデックスをセットしてください(A列:”0″, C列:”2″, 末尾列:”-1″)#{EL}
SelectConfC
C: アウトプットTSVが格納される複数行文字列型データを選択してください (更新) *
SelectConfInY
InY: インプットTSVの行数(高さ)を格納する数値型データを選択してください (更新)
SelectConfInX
InX: インプットTSVの列数(幅)を格納する数値型データを選択してください (更新)
SelectConfOutY
OutY: アウトプットTSVの行数(高さ)が格納される数値型データを選択してください (更新)
SelectConfOutX
OutX: アウトプットTSVの列数(幅)が格納される数値型データを選択してください (更新)
Script (click to open)
// Script Example of Business Process Automation
// for 'engine type: 3' ("GraalJS standard mode")
// cf. 'engine type: 2' ("GraalJS Nashorn compatible mode") (renamed from "GraalJS" at 20230526)


//////// START "main()" /////////////////////////////////////////////////////////////////
main();
function main(){ 

//// == Config Retrieving / 工程コンフィグの参照 ==
const strTsv        = configs.get        ( "StrConfA" );       // REQUIRED
  if( strTsv === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {A: TSV} is empty \n" );
  }
  const arr2dTsv    = parseAsRectangular ( strTsv );           // as arr2dTSV[Y][X]


const strSeparator  = configs.get        ( "OptionConfB0" );   /// REQUIRED (SELECT_ITEM)
  // "comma", "dot", "space"

const strStartIndex = configs.get        ( "StrConfB1" );      // not required
  let numStartIndex = Number( strStartIndex );
  if ( isNaN(numStartIndex) ) {
    numStartIndex = 0;
  } else if ( numStartIndex < 0 ) {
    numStartIndex = arr2dTsv[0].length + numStartIndex;
  }
  engine.log( " AutomatedTask Runtime: StartIndex auto-set as " + numStartIndex );
  if( arr2dTsv[0].length <= numStartIndex ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Start-Index must be less than the number of columns. \n" );
  }
const strEndIndex   = configs.get        ( "StrConfB2" );      // not required
  let numEndIndex = strEndIndex.trim() === "" ? NaN : Number( strEndIndex );
  if ( isNaN(numEndIndex) ) {
    numEndIndex = arr2dTsv[0].length;
  } else if ( numEndIndex < 0 ) {
    numEndIndex = arr2dTsv[0].length + numEndIndex;
  }
  engine.log( " AutomatedTask Runtime: EndIndex auto-set as " + numEndIndex );
  if( numEndIndex <= numStartIndex ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Start-Index must be less than End-Index. \n" );
  }
const strPocketC    = configs.getObject ( "SelectConfC" );     // REQUIRED
const numPocketInY  = configs.getObject ( "SelectConfInY" );   // not required
const numPocketInX  = configs.getObject ( "SelectConfInX" );   // not required
const numPocketOutY = configs.getObject ( "SelectConfOutY" );  // not required
const numPocketOutX = configs.getObject ( "SelectConfOutX" );  // not required



//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)



//// == Calculating / 演算 ==
let arrOutputTsv  = [];

for ( let i = 0; i < arr2dTsv.length; i++ ) {
  let arrRow = arr2dTsv[i];   // 元の行データ
  let arrOutputRow = [];

  for ( let j = 0; j < arrRow.length; j++ ) {      // 処理対象の列かどうかの判定
    if (j >= numStartIndex && j < numEndIndex) {   // 処理対象の列は桁区切りを適用
      let processedValue = arrRow[j];
      if (strSeparator === "comma") {
        processedValue = processedValue.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
      } else if (strSeparator === "dot") {
        processedValue = processedValue
          .replace(/(\d)\.(?=\d)/g, '$1,')   // 小数点を一時的にカンマに
          .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.')   // 桁区切りをドットに
          .replace(/(\d),(\d)/g, '$1.$2');   // 一時的なカンマをドットに戻す
      } else if (strSeparator === "space") {
        processedValue = processedValue
          .replace(/(\d)\.(?=\d)/g, '$1,')   // 小数点を一時的にカンマに
          .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 ')   // 桁区切りをスペースに
          .replace(/(\d),(\d)/g, '$1.$2');   // 一時的なカンマをドットに戻す
      }
      arrOutputRow.push(processedValue);
    } else {
      arrOutputRow.push(arrRow[j]);      // 処理対象外の列は元の値をそのまま使用
    }
  }
  arrOutputTsv.push(arrOutputRow.join('\t'));
}



//// == Data Updating / ワークフローデータへの代入 ==
/// ref) Retrieving / Updating from ScriptTasks
/// https://questetra.zendesk.com/hc/en-us/articles/360024574771-R2301
/// https://questetra.zendesk.com/hc/ja/articles/360024574771-R2301

if ( strPocketC !== null ){ 
  engine.setData( strPocketC, arrOutputTsv?.join( '\n' ) ?? "" );
}

if ( numPocketInY !== null ){ 
  engine.setData( numPocketInY, new java.math.BigDecimal( arr2dTsv.length ) );
}
if ( numPocketInX !== null ){ 
  engine.setData( numPocketInX, new java.math.BigDecimal( arr2dTsv[0].length ) );
}
if ( numPocketOutY !== null ){ 
  engine.setData( numPocketOutY, new java.math.BigDecimal( arrOutputTsv.length ) );
}
if ( numPocketOutX !== null ){ 
  engine.setData( numPocketOutX, new java.math.BigDecimal( arrOutputTsv[0].split("\t").length ) );
}



} //////// END "main()" /////////////////////////////////////////////////////////////////



/**
 * Parses a TSV (Tab-Separated Values) string and returns a 2D array with rectangular shape.
 * This function ensures that each row in the resulting 2D array has the same number of columns,
 * equal to the widest row in the original TSV input. Shorter rows are padded with empty strings.
 * Blank lines in the input are ignored.
 * Additionally, the function logs the minimum and maximum column counts (excluding blank lines),
 * along with the total number of lines and count of blank lines.
 * 
 * TSV(タブ区切り値)形式の文字列を解析し、2次元の配列として整形して返します。
 * 入力されたTSV文字列を行単位で分割し、各行のセル数をそろえて「長方形(矩形)」の形に整えます。
 * 最もセル数が多い行に合わせて、セル数が足りない行には空文字列("")を補完します。
 * 空行(中身が空の行)は無視されます。
 * また、最小列数・最大列数・全体の行数・空行の数をログに出力します(engine.log)。
 * 
 * 
 * @param {string} strTsv - The raw TSV string, with rows separated by newline characters (`\n`) 
 *                          and cells separated by tab characters (`\t`).
 * 
 * @returns {string[][]} A two-dimensional array where each sub-array represents a row from the TSV input,
 *                       padded with empty strings to ensure uniform column width.
 * 
 * @example
 * const tsv = "a\tb\tc\n1\t2\nx\ty\tz\tw\n";
 * const result = parseAsRectangular(tsv);
 * // result:
 * // [
 * //   ["a", "b", "c", ""],
 * //   ["1", "2", "", ""],
 * //   ["x", "y", "z", "w"]
 * // ]
 */

function parseAsRectangular( strTsv ){
  const arrTsv = strTsv.split("\n");

  /// Get numMinWidth and numMaxWidth (blank lines are excluded)
  let numMinWidth   = Infinity; // cf. String-Type Max: 1 million
  let numMaxWidth   = 0;
  let numBlanklines = 0;
  for( let i = 0; i < arrTsv.length; i++ ){
    if( arrTsv[i] === "" ){ // Skip blank lines
      numBlanklines += 1;
      continue;
    }
    let arrCells = arrTsv[i].split("\t");
    if( numMinWidth > arrCells.length ){ numMinWidth = arrCells.length; }
    if( numMaxWidth < arrCells.length ){ numMaxWidth = arrCells.length; }
  }
  engine.log( " AutomatedTask TsvDataCheck:" + 
              " MinWidth:" + numMinWidth +
              " MaxWidth:" + numMaxWidth +
              " Lines:" + arrTsv.length +
              " (BlankLines:" + numBlanklines + ")" );

  /// Get numMinWidth and numMaxWidth (blank lines are excluded)
  let arr2dTsv      = [];
  for( let i = 0; i < arrTsv.length; i++ ){
    if( arrTsv[i] === "" ){ // Skip blank lines
      continue;
    }
    let arrTmp = [];
    let arrCells = arrTsv[i].split("\t");
    for( let j = 0; j < numMaxWidth; j++ ){
      if( j < arrCells.length ){
        arrTmp[j] = arrCells[j];
      }else{
        arrTmp[j] = "";
      }
    }
    arr2dTsv.push( arrTmp );
  }

  return arr2dTsv;
}



/*
### NOTES
- When the process reaches this [Automated Step], the "Formatting" is automatically executed.
    - Helps improve the visibility of numerical data.
    - Convenient for pre-processing of data sharing (such as email sending, posting to CollabChat, etc.)
- The specified column range (from the START index to just before the END index) is automatically extracted.
    - The column index starts at "0" (counting from the beginning, first column is `0`).
    - A "negative value" can also be set for the column index (counting from the end, last column is `-1`).
    - If the START index is omitted, extraction will start from the first column of the TSV.
    - If the END index is omitted, extraction will start up to the last column of the TSV.
- Detects numbers with more than three digits in the Cell text.
    - Adds thousand separator to each number.
    - A comma, dot, or space can be specified as the digit separator.
    - Note that this replacement will also be applied to decimals, postal codes and years.

### NOTES-ja
- 案件プロセスがこの自動工程に到達した際、TSVテキストが読み込まれ「フォーマット処理」が自動実行されます
    - 数値データの視認性を向上させるのに役立ちます
    - データ共有(メール送信やCollabChatへの自動投稿など)の前処理として便利なアドオン自動工程です
- 指定の列範囲(STARTインデックスからENDインデックスの手前まで)が、自動抽出されます
    - 列インデックスは「0」から始まります(先頭から数える/先頭列は `0`)
    - 列インデックスには「負の値」も設定可能です(末尾から数える/末尾列は `-1`)
    - STARTインデックス指定が省略された場合、TSVの最初の列から抽出されます
    - ENDインデックス指定が省略された場合、TSVの最後の列までが抽出されます
- 各セルテキスト中の4桁以上数値(数字4連続以上)を検出します
    - 各数値に対してケタ区切記号を付与します
    - 桁区切り記号には、カンマ、ドットもしくはスペースが指定可能です
    - この自動変換は、小数部や郵便番号や年号にも適用されてしまう点に注意が必要です

### APPENDIX
- TSV (Tab Separated Values) text is assumed to be rectangular data.
    - TSV text: monthly sales summary, monthly access summary, PIVOT table, etc.
    - Non-rectangular data is automatically formatted with an empty string (adjusted to the longest number of columns).
    - Blank lines (including trailing newlines) are ignored.
- Indexes:
    - Indexes start from 0 (first column is `0`).
    - For example, the third column from the left (so-called column C) has index `2`.
    - Negative indexes are counted from the end (last column is `-1`).
    - For example, the third column from the right has index `-3`.
- The number of rows (height) and columns (width) of the input/output TSV can be stored in Numeric data.
- Examples:
    - Input: `$12345678.90`
    - Output: `$12,345,678.90`
    - Input: `€12345.00`
    - Output: `€12,345.00`
    - Input: `12345678.90123`
    - Output: `12,345,678.90,123` (not good)
    - Input: `0120-345-678`
    - Output: `0,120-345-678` (not good)

### APPENDIX-ja
- TSV(Tab Separated Values)テキストは、矩形データを前提とします
    - TSVテキスト: 月次売上集計、月次アクセス集計、PIVOTテーブル、など
    - 矩形でないデータは、空文字列によって自動整形されます(最も長い列数に合わせる)
    - 空行(末尾改行を含む)は無視されます
- インデックスの理解:
    - インデックスは0から始まります(先頭列は `0`)
    - 例えば、左から3番目の列(いわゆるC列)は、インデックス `2` となります
    - 負のインデックスは末尾から数えます(末尾列は `-1`)
    - 例えば、右から3番目の列は、インデックス `-3` となります
- インプットTSVおよびアウトプットTSVの行数(高さ)と列数(幅)を数値型データ項目に格納できます
- Examples:
    - Input: `$12345678.90`
    - Output: `$12,345,678.90`
    - Input: `€12345.00`
    - Output: `€12,345.00`
    - Input: `12345678.90123`
    - Output: `12,345,678.90,123` (好ましくない例)
    - Input: `0120-345-678`
    - Output: `0,120-345-678` (好ましくない例)
*/

Download

warning 自由改変可能な JavaScript (ECMAScript) コードです。いかなる保証もありません。
(アドオン自動工程のインストールは Professional editionでのみ可能です)

Notes

  • 案件プロセスがこの自動工程に到達した際、TSVテキストが読み込まれ「フォーマット処理」が自動実行されます
    • 数値データの視認性を向上させるのに役立ちます
    • データ共有(メール送信やCollabChatへの自動投稿など)の前処理として便利なアドオン自動工程です
  • 指定の列範囲(STARTインデックスからENDインデックスの手前まで)が、自動抽出されます
    • 列インデックスは「0」から始まります(先頭から数える/先頭列は 0
    • 列インデックスには「負の値」も設定可能です(末尾から数える/末尾列は -1
    • STARTインデックス指定が省略された場合、TSVの最初の列から抽出されます
    • ENDインデックス指定が省略された場合、TSVの最後の列までが抽出されます
  • 各セルテキスト中の4桁以上数値(数字4連続以上)を検出します
    • 各数値に対してケタ区切記号を付与します
    • 桁区切り記号には、カンマ、ドットもしくはスペースが指定可能です
    • この自動変換は、小数部や郵便番号や年号にも適用されてしまう点に注意が必要です

Capture

指定の列範囲に桁区切り書式を適用します。START列からEND列の手前まで(ENDは含まない)に適用されます。インデックスは「0」から始まります。負のインデックスは末尾から逆算されます。STARTを省略した場合は「先頭から」、ENDを省略した場合は「末尾まで」となります。

Appendix

  • TSV(Tab Separated Values)テキストは、矩形データを前提とします
    • TSVテキスト: 月次売上集計、月次アクセス集計、PIVOTテーブル、など
    • 矩形でないデータは、空文字列によって自動整形されます(最も長い列数に合わせる)
    • 空行(末尾改行を含む)は無視されます
  • インデックスの理解:
    • インデックスは0から始まります(先頭列は 0
    • 例えば、左から3番目の列(いわゆるC列)は、インデックス 2 となります
    • 負のインデックスは末尾から数えます(末尾列は -1
    • 例えば、右から3番目の列は、インデックス -3 となります
  • インプットTSVおよびアウトプットTSVの行数(高さ)と列数(幅)を数値型データ項目に格納できます
  • Examples:
    • Input: $12345678.90
    • Output: $12,345,678.90
    • Input: ?12345.00
    • Output: ?12,345.00
    • Input: 12345678.90123
    • Output: 12,345,678.90,123 (好ましくない例)
    • Input: 0120-345-678
    • Output: 0,120-345-678 (好ましくない例)

See Also

上部へスクロール

Questetra Supportをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む