1
0
mirror of synced 2024-11-15 10:47:41 +01:00

Tidied up 'To Table' operation, adding better CSV parsing support.

This commit is contained in:
n1474335 2018-05-04 16:10:22 +00:00
parent 8fc5f59647
commit 8556bdcdeb
4 changed files with 43 additions and 58 deletions

View File

@ -737,37 +737,43 @@ const Utils = {
* Parses CSV data and returns it as a two dimensional array or strings. * Parses CSV data and returns it as a two dimensional array or strings.
* *
* @param {string} data * @param {string} data
* @param {string[]} [cellDelims=[","]]
* @param {string[]} [lineDelims=["\n", "\r"]]
* @returns {string[][]} * @returns {string[][]}
* *
* @example * @example
* // returns [["head1", "head2"], ["data1", "data2"]] * // returns [["head1", "head2"], ["data1", "data2"]]
* Utils.parseCSV("head1,head2\ndata1,data2"); * Utils.parseCSV("head1,head2\ndata1,data2");
*/ */
parseCSV: function(data) { parseCSV: function(data, cellDelims=[","], lineDelims=["\n", "\r"]) {
let b, let b,
ignoreNext = false, next,
renderNext = false,
inString = false, inString = false,
cell = "", cell = "",
line = [], line = [],
lines = []; lines = [];
// Remove BOM, often present in Excel CSV files
if (data.length && data[0] === "\uFEFF") data = data.substr(1);
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
b = data[i]; b = data[i];
if (ignoreNext) { next = data[i+1] || "";
if (renderNext) {
cell += b; cell += b;
ignoreNext = false; renderNext = false;
} else if (b === "\\") { } else if (b === "\\") {
cell += b; renderNext = true;
ignoreNext = true;
} else if (b === "\"" && !inString) { } else if (b === "\"" && !inString) {
inString = true; inString = true;
} else if (b === "\"" && inString) { } else if (b === "\"" && inString) {
inString = false; if (next === "\"") renderNext = true;
} else if (b === "," && !inString) { else inString = false;
} else if (!inString && cellDelims.indexOf(b) >= 0) {
line.push(cell); line.push(cell);
cell = ""; cell = "";
} else if ((b === "\n" || b === "\r") && !inString) { } else if (!inString && lineDelims.indexOf(b) >= 0) {
line.push(cell); line.push(cell);
cell = ""; cell = "";
lines.push(line); lines.push(line);

View File

@ -67,7 +67,6 @@ const Categories = [
"Encode text", "Encode text",
"Decode text", "Decode text",
"Swap endianness", "Swap endianness",
"To Table",
] ]
}, },
{ {
@ -183,6 +182,7 @@ const Categories = [
"To Lower case", "To Lower case",
"Add line numbers", "Add line numbers",
"Remove line numbers", "Remove line numbers",
"To Table",
"Reverse", "Reverse",
"Sort", "Sort",
"Unique", "Unique",

View File

@ -616,26 +616,22 @@ const OperationConfig = {
}, },
"To Table": { "To Table": {
module: "Default", module: "Default",
description: "Renders data as a table. Data can be split on different characters and output as a HTML or ASCII table with optional header row.", description: "Data can be split on different characters and rendered as an HTML or ASCII table with an optional header row.<br><br>Supports the CSV (Comma Separated Values) file format by default. Change the cell delimiter argument to <code>\\t</code> to support TSV (Tab Separated Values) or <code>|</code> for PSV (Pipe Separated Values).<br><br>You can enter as many delimiters as you like. Each character will be treat as a separate possible delimiter.",
inputType: "string", inputType: "string",
outputType: "html", outputType: "html",
highlight: false,
highlightReverse: false,
manualBake: false,
args: [ args: [
{ {
name: "Select separator", name: "Cell delimiters",
type: "populateOption", type: "binaryShortString",
value: ToTable.SEPARATORS,
target: 1
},
{
name: "Separator",
type: "string",
value: "," value: ","
}, },
{ {
name: "First row header?", name: "Row delimiters",
type: "binaryShortString",
value: "\\n\\r"
},
{
name: "Make first row header",
type: "boolean", type: "boolean",
value: false value: false
}, },

View File

@ -2,19 +2,14 @@
* ToTable operations. * ToTable operations.
* *
* @author Mark Jones [github.com/justanothermark] * @author Mark Jones [github.com/justanothermark]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*
* @namespace * @namespace
*/ */
import Utils from "../Utils.js";
const ToTable = { const ToTable = {
/**
* @constant
* @default
*/
SEPARATORS: [
{name: "Comma", value: ","},
{name: "Tab", value: "\\t"},
{name: "Pipe", value: "|"},
{name: "Custom", value: ""}
],
/** /**
* @constant * @constant
@ -25,6 +20,7 @@ const ToTable = {
"HTML" "HTML"
], ],
/** /**
* To Table operation. * To Table operation.
* *
@ -33,42 +29,26 @@ const ToTable = {
* @returns {html} * @returns {html}
*/ */
runToTable: function (input, args) { runToTable: function (input, args) {
let separator = args[1]; const [cellDelims, rowDelims, firstRowHeader, format] = args;
let firstRowHeader = args[2];
let format = args[3];
let tableData = [];
// If the separator contains any tabs, convert them to tab characters.
separator = separator.replace("\\t", "\t");
// Process the input into a nested array of elements. // Process the input into a nested array of elements.
let rows = input.split("\n"); const tableData = Utils.parseCSV(input, cellDelims.split(""), rowDelims.split(""));
rows.forEach(function(element) {
if (separator === "") { if (!tableData.length) return "";
tableData.push([element]);
} else {
tableData.push(element.split(separator));
}
});
// Render the data in the requested format. // Render the data in the requested format.
let output = "";
switch (format) { switch (format) {
case "ASCII": case "ASCII":
output = asciiOutput(tableData); return asciiOutput(tableData);
break; case "HTML":
default: default:
output = htmlOutput(tableData); return htmlOutput(tableData);
break;
} }
return output;
/** /**
* Outputs an array of data as an ASCII table. * Outputs an array of data as an ASCII table.
* *
* @param {Array[]} tableData * @param {string[][]} tableData
* @returns {string} * @returns {string}
*/ */
function asciiOutput(tableData) { function asciiOutput(tableData) {
@ -137,6 +117,9 @@ const ToTable = {
/** /**
* Outputs a table of data as a HTML table. * Outputs a table of data as a HTML table.
*
* @param {string[][]} tableData
* @returns {string}
*/ */
function htmlOutput(tableData) { function htmlOutput(tableData) {
// Start the HTML output with suitable classes for styling. // Start the HTML output with suitable classes for styling.