浏览代码

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

n1474335 7 年之前
父节点
当前提交
8556bdcdeb
共有 4 个文件被更改,包括 42 次插入57 次删除
  1. 16 10
      src/core/Utils.js
  2. 1 1
      src/core/config/Categories.js
  3. 8 12
      src/core/config/OperationConfig.js
  4. 17 34
      src/core/operations/ToTable.js

+ 16 - 10
src/core/Utils.js

@@ -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;
-                ignoreNext = true;
+                renderNext = true;
             } else if (b === "\"" && !inString) {
             } else if (b === "\"" && !inString) {
                 inString = true;
                 inString = true;
             } else if (b === "\"" && inString) {
             } else if (b === "\"" && inString) {
-                inString = false;
-            } else if (b === "," && !inString) {
+                if (next === "\"") renderNext = true;
+                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);

+ 1 - 1
src/core/config/Categories.js

@@ -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",

+ 8 - 12
src/core/config/OperationConfig.js

@@ -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",
-                type: "populateOption",
-                value: ToTable.SEPARATORS,
-                target: 1
+                name: "Cell delimiters",
+                type: "binaryShortString",
+                value: ","
             },
             },
             {
             {
-                name: "Separator",
-                type: "string",
-                value: ","
+                name: "Row delimiters",
+                type: "binaryShortString",
+                value: "\\n\\r"
             },
             },
             {
             {
-                name: "First row header?",
+                name: "Make first row header",
                 type: "boolean",
                 type: "boolean",
                 value: false
                 value: false
             },
             },

+ 17 - 34
src/core/operations/ToTable.js

@@ -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];
-        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");
+        const [cellDelims, rowDelims, firstRowHeader, format] = args;
 
 
         // Process the input into a nested array of elements.
         // Process the input into a nested array of elements.
-        let rows = input.split("\n");
-        rows.forEach(function(element) {
-            if (separator === "") {
-                tableData.push([element]);
-            } else {
-                tableData.push(element.split(separator));
-            }
-        });
+        const tableData = Utils.parseCSV(input, cellDelims.split(""), rowDelims.split(""));
+
+        if (!tableData.length) return "";
 
 
         // 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);
-                break;
-
+                return asciiOutput(tableData);
+            case "HTML":
             default:
             default:
-                output = htmlOutput(tableData);
-                break;
+                return htmlOutput(tableData);
         }
         }
 
 
-        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.