#TSV-String: Basic Math on Numeric Column
Adds result of a numerical calculation as a new column. The result of binary calculations such as adding column A and column B, or multiplying column C by 1.1, is added to the end of each TSV row. Subtraction, division, remainders, and powers are also supported.
Configs for this Auto Step
- StrConfA
- A: Set Input TSV String *#{EL}
- BoolConfAx
- Ax: Regard First-line as Header: No or Yes
- OptionConfB
- B: Select OPERATOR *
- StrConfX
- X: Set ID of First Operand Column (Col-A: “0”, Col-C: “2”)#{EL}
- StrConfXv
- Xv: Set Default Value of First Operand X (eg: “1.1”)#{EL}
- StrConfY
- Y: Set ID of Second Operand Column (Col-B: “1”, Col-D: “3”)#{EL}
- StrConfYv
- Yv: Set Default Value of Second Operand Y (eg: “1.1”)#{EL}
- SelectConfC
- C: Select STRING DATA to store Output TSV (update) *
- BoolConfCx
- Cx: Thousands separator: Off or On
- SelectConfDy
- Dy: Select NUMERIC for Number of Input TSV Lines (update)
- SelectConfDx
- Dx: Select NUMERIC for Number of Input TSV Cols (update)
- SelectConfEy
- Ey: Select NUMERIC for Number of Output TSV Lines (update)
- SelectConfEx
- Ex: Select NUMERIC for Number of Output TSV Lines (update)
- StrConfF
- F: If Separator On, Set Minimum Fraction Digits (defalut: “0”)#{EL}
- StrConfG
- G: If Separator On, Set Maximum Fraction Digits (defalut: “3”)#{EL}
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" );
}
// get TSV as Array-Array (2d Array)
const arr2dTsv = parseAsRectangular ( strTsv ); // [rowY,colX]
let numInputTsvLines = arr2dTsv.length;
let numInputTsvCols = arr2dTsv[0].length;
const boolHeaderOn = configs.getObject ( "BoolConfAx" ); // TOGGLE
// https://questetra.zendesk.com/hc/ja/articles/360024574471-R2300 "Boolean object"
const strOperator = configs.get ( "OptionConfB" ); /// REQUIRED (SELECT_ITEM)
// "add", "subtract", "multiply", "divide", "remainder", "power"
const strOperandXid = configs.get ( "StrConfX" ); // not required
let numOperandXid = parseInt( strOperandXid, 10 ); // Int or NaN
const strOperandXv = configs.get ( "StrConfXv" ); // not required
let numOperandXv = parseFloat( strOperandXv ); // Float or NaN
const strOperandYid = configs.get ( "StrConfY" ); // not required
let numOperandYid = parseInt( strOperandYid, 10 ); // Int or NaN
const strOperandYv = configs.get ( "StrConfYv" ); // not required
let numOperandYv = parseFloat( strOperandYv ); // Float or NaN
const strPocketC = configs.getObject ( "SelectConfC" ); // REQUIRED
const boolSeparatorOn = configs.getObject ( "BoolConfCx" ); // TOGGLE
const numPocketDy = configs.getObject ( "SelectConfDy" ); // not required
const numPocketDx = configs.getObject ( "SelectConfDx" ); // not required
const numPocketEy = configs.getObject ( "SelectConfEy" ); // not required
const numPocketEx = configs.getObject ( "SelectConfEx" ); // not required
const strDigitMin = configs.get ( "StrConfF" ); // not required
let numDigitMin = parseInt( strDigitMin, 10 ); // Int or NaN
const strDigitMax = configs.get ( "StrConfG" ); // not required
let numDigitMax = parseInt( strDigitMax, 10 ); // Int or NaN
//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)
//// == Calculating / 演算 ==
let arrOutputTsv = [];
if ( boolHeaderOn ){
let arrTmp = arr2dTsv.shift(); // Remove First Element
arrTmp.push ( strOperator );
arrOutputTsv.push ( arrTmp.join( '\t' ) );
}
for ( let i = 0; i < arr2dTsv.length; i++ ) {
let arrTmp = arr2dTsv[i].slice();
let numX;
if ( !isNaN(numOperandXid) ) {
numX = parseFloat(arr2dTsv[i][numOperandXid].replace(/,/g, ''));
}
if ( isNaN(numX) ) { // numOperandXidがNaNの場合、またはTSVからのパース結果がNaNの場合
numX = numOperandXv;
}
if ( isNaN(numX) ){
arrTmp.push ( "#N/A" );
arrOutputTsv.push ( arrTmp.join( '\t' ) );
continue;
}
let numY;
if ( !isNaN(numOperandYid) ) {
numY = parseFloat(arr2dTsv[i][numOperandYid].replace(/,/g, ''));
}
if ( isNaN(numY) ) { // numOperandYidがNaNの場合、またはTSVからのパース結果がNaNの場合
numY = numOperandYv;
}
if ( isNaN(numY) ){
arrTmp.push ( "#N/A" );
arrOutputTsv.push ( arrTmp.join( '\t' ) );
continue;
}
if ( strOperator === 'divide' && numY === 0 ) {
arrTmp.push("#DIV/0!");
arrOutputTsv.push(arrTmp.join('\t'));
continue;
}
let numResult = 0;
switch ( strOperator ) {
case 'add': numResult = numX + numY; break;
case 'subtract': numResult = numX - numY; break;
case 'multiply': numResult = numX * numY; break;
case 'divide': numResult = numX / numY; break;
case 'remainder': numResult = numX % numY; break;
case 'power': numResult = numX ** numY; break;
default: throw new Error( "\n AutomatedTask RuntimeError:" +
" Unsupported operator: " + strOperator + "\n" );
}
if ( boolSeparatorOn ){
let formatOptions = {};
if ( !isNaN(numDigitMin) ) formatOptions.minimumFractionDigits = numDigitMin;
if ( !isNaN(numDigitMax) ) formatOptions.maximumFractionDigits = numDigitMax;
arrTmp.push( numResult.toLocaleString( undefined, formatOptions ) );
} else {
arrTmp.push ( numResult );
}
arrOutputTsv.push ( arrTmp.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 ( numPocketDy !== null ){
engine.setData( numPocketDy, new java.math.BigDecimal( numInputTsvLines ) );
}
if ( numPocketDx !== null ){
engine.setData( numPocketDx, new java.math.BigDecimal( numInputTsvCols ) );
}
if ( numPocketEy !== null ){
engine.setData( numPocketEy, new java.math.BigDecimal( arrOutputTsv.length ) );
}
if ( numPocketEx !== null ){
engine.setData( numPocketEx, 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 calculation processing is automatically executed.
- The calculation result is added to the rightmost column at the output TSV.
- Binary operations can be set using numeric column X and numeric column Y (column IDs starting from zero).
- One of XY can also be set to a fixed value.
- TSV (Tab Separated Values) text is assumed to be rectangular data.
- TSV text: monthly sales tally, monthly access tally, etc.
- Data that is not rectangular is automatically formatted with blank characters.
- Blank lines (including trailing newlines) are ignored.
- Numeric columns are parsed with JavaScript `parseFloat()` after removing commas (thousand separators).
- The characters accepted are plus/minus signs, decimal digits, decimal points (.), exponent indicators, and the infinity symbol.
- If it cannot be converted to a number, it is calculated using the default value.
- If no column ID is specified for XY, it is calculated using the default value (fixed value).
- If the default value is also not set, `#N/A` will be output.
- If the value of Y is "0" during division, `#DIV/0!` will be output.
- To arrange the sort order of the output TSV, place the add-on step "TSV String, Convert" downstream in the workflow.
- https://support.questetra.com/addons/tsv-string-convert-2021/
### NOTES-ja
- 案件プロセスがこの自動工程に到達した際、TSVテキストが読み込まれ「計算処理」が自動実行されます
- 計算結果が最右列に列追加されたTSVが出力されます
- 数値列Xと数値列Yによる二項演算が設定可能です(列IDはゼロ始まりで設定してください)
- XYの一方を固定値に設定することも可能です
- TSV(Tab Separated Values)テキストは、矩形データを前提とします
- TSVテキスト: 月次売上集計、月次アクセス集計、など
- 矩形でないデータは、空文字によって自動整形されます
- 空行(末尾改行を含む)は無視されます
- 数値列は、カンマ(桁区切り文字)を除去したうえで、JavaScript `parseFloat()` で解析されます
- 正負符号、数値、小数点 (.)、指数記号、および `Infinity` が認識可能です
- (以外の文字に遭遇したら、その文字の前までの値を返します)
- 数値に変換できなかった場合は、「デフォルト値」にて計算されます
- XYに列IDを指定しなかった場合は、「デフォルト値」にて計算されます(固定値)
- 「デフォルト値」も未設定だった場合、 `#N/A` が出力されます
- 除算時にYの値が "0" だった場合、 `#DIV/0!` が出力されます
- 出力TSVの並び順を変更したい場合は、ワークフロー下流に『TSV 文字列, 変換』を配置します。
- https://support.questetra.com/ja/addons/tsv-string-convert-2021/
### APPENDIX
- If the first line is a header row, the column name of the calculation result will be the operator name.
- "add", "subtract", "multiply", "divide", "remainder" or "power"
- e.g.: Add column A (column ID: "0") and column B (column ID: "1")
- Operator: `Addition: X+Y`
- Column ID of X: `0`
- Column ID of Y: `1`
- e.g.: Calculate 1.1 times the value of column C (column ID: "2")
- Operator: `Multiplication: X*Y`
- Column ID of X: `2`
- Default value of X: `0`
- Column ID of Y: `null` (not set)
- Default value of Y: "1.1"
### APPENDIX-ja
- 1行目がヘッダ行の場合、計算結果列の列名は演算子名となります
- "add", "subtract", "multiply", "divide", "remainder", "power"
- eg: A列(列ID:"0")とB列(列ID:"1") の加算
- 演算子: `加算: X+Y`
- Xの列ID: `0`
- Yの列ID: `1`
- eg: C列 (列ID:"2") の値の1.1倍を計算
- 演算子: `乗算: X*Y`
- Xの列ID: `2`
- Xのデフォルト値: `0`
- Yの列ID: `null` (未設定)
- Yのデフォルト値: `1.1`
*/
Download
- tsv-string-basic-math-on-numeric-column-2025.xml
- 2025-07-02 (C) Questetra, Inc. (MIT License)
Freely modifiable JavaScript (ECMAScript) code. No warranty of any kind.
(Installing Addon Auto-Steps are available only on the Professional edition.)
(Installing Addon Auto-Steps are available only on the Professional edition.)
Notes
- When the process reaches this [Automated Step], the “calculation process” is automatically executed.
- The calculation result is added to the rightmost column at the output TSV.
- Binary operations can be set using numeric column X and numeric column Y (column IDs starting from zero).
- One of XY can also be set to a fixed value.
- TSV (Tab Separated Values) text is assumed to be rectangular data.
- TSV text: monthly sales tally, monthly access tally, etc.
- Data that is not rectangular is automatically formatted with blank characters.
- Blank lines (including trailing newlines) are ignored.
- Numeric columns are parsed with JavaScript
parseFloat()after removing commas (thousand separators).- The characters accepted are plus/minus sign, decimal digits, decimal point (.), exponent indicator, and the
Infinityliteral. - If it cannot be converted to a number, it is calculated using the “default value”.
- If no column ID is specified for XY, it is calculated using the “default value” (fixed value).
- If the “default value” is also not set,
#N/Awill be output. - If the value of Y is “0” during division,
#DIV/0!will be output.
- The characters accepted are plus/minus sign, decimal digits, decimal point (.), exponent indicator, and the
- To arrange the sort order of the output TSV, place “TSV String, Convert” downstream in the workflow.
Capture


Appendix
- If the first line is a header row, the column name of the calculation result will be the operator name.
- “add”, “subtract”, “multiply”, “divide”, “remainder” or “power”
- e.g.: Add column A (column ID: “0”) and column B (column ID: “1”)
- Operator:
Addition: X+Y - Column ID of X:
0 - Column ID of Y:
1
- Operator:
- e.g.: Calculate 1.1 times the value of column C (column ID: “2”)
- Operator:
Multiplication: X*Y - Column ID of X:
2 - Default value of X:
0 - Column ID of Y:
null(not set) - Default value of Y: “1.1”
- Operator:
