facebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskype
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
8.4 KiB
237 lines
8.4 KiB
/** |
|
* This base class contains utility methods for dealing with formats such as CSV (Comma |
|
* Separated Values) as specified in <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>. |
|
* |
|
* The base class implements the mechanics and is governed by these config options: |
|
* |
|
* * `{@link #delimiter}` |
|
* * `{@link #lineBreak}` |
|
* * `{@link #quote}` |
|
* |
|
* These options affect the `{@link #method-encode}` and `{@link #method-decode}` methods. |
|
* When *decoding*, however, `{@link #lineBreak}` is ignored and instead each line can |
|
* be separated by any standard line terminator character or character sequence: |
|
* |
|
* * ```\u000a``` |
|
* * ```\u000d``` |
|
* * ```\u000d\u000a``` |
|
* |
|
* Strings which contain the {@link #delimiter} character are quoted using the |
|
* {@link #quote} character, and any internal {@link #quote} characters are doubled. |
|
* |
|
* *Important* |
|
* While the primary use case is to encode strings, other atomic data types can be encoded |
|
* as values within a line such as: |
|
* |
|
* * Number |
|
* * Boolean |
|
* * Date (encoded as an <a href="http://www.iso.org/iso/home/standards/iso8601.htm">ISO 8601</a> date string.) |
|
* * null (encoded as an empty string.) |
|
* * undefined (encoded as an empty string.) |
|
* |
|
* Not that when *decoding*, all data is read as strings. This class does not convert |
|
* incoming data. To do that, use an {@link Ext.data.reader.Array ArrayReader}. |
|
* |
|
* See `{@link Ext.util.CSV}` and `{@link Ext.util.TSV}` for pre-configured instances. |
|
* |
|
* @since 5.1.0 |
|
*/ |
|
Ext.define('Ext.util.DelimitedValue', { |
|
/** |
|
* @cfg {String} dateFormat |
|
* The {@link Ext.Date#format format} to use for dates |
|
*/ |
|
dateFormat: 'C', |
|
|
|
/** |
|
* @cfg {String} delimiter |
|
* The string used to separate the values in a row. Common values for this config |
|
* are comma (",") and tab ("\t"). See `{@link Ext.util.CSV}` and `{@link Ext.util.TSV}` |
|
* for pre-configured instances of these formats. |
|
*/ |
|
delimiter: '\t', |
|
|
|
/** |
|
* @cfg {String} lineBreak |
|
* The string used by `{@link #encode}` to separate each row. The `{@link #decode}` |
|
* method accepts all forms of line break. |
|
*/ |
|
lineBreak: '\n', |
|
|
|
/** |
|
* @cfg {String} quote |
|
* The character to use as to quote values that contain the special `delimiter` |
|
* or `{@link #lineBreak}` characters. |
|
*/ |
|
quote: '"', |
|
|
|
parseREs: {}, |
|
quoteREs: {}, |
|
|
|
lineBreakRe: /\r?\n/g, |
|
|
|
constructor: function (config) { |
|
if (config) { |
|
Ext.apply(this, config); |
|
} |
|
}, |
|
|
|
/** |
|
* Decodes a string of encoded values into an array of rows. Each row is an array of |
|
* strings. |
|
* |
|
* Note that this function does not convert the string values in each column into |
|
* other data types. To do that, use an {@link Ext.data.reader.Array ArrayReader}. |
|
* |
|
* For example: |
|
* |
|
* Ext.util.CSV.decode('"foo ""bar"", bletch",Normal String,2010-01-01T21:45:32.004Z\u000a3.141592653589793,1,false'); |
|
* |
|
* produces the following array of string arrays: |
|
* |
|
* [ |
|
* ['foo "bar", bletch','Normal String', '2010-01-01T21:45:32.004Z'], |
|
* ['3.141592653589793', '1', 'false'] |
|
* ] |
|
* |
|
* @param {String} input The string to parse. |
|
* |
|
* @param {String} [delimiter] The column delimiter to use if the default value |
|
* of {@link #cfg-delimiter delimiter} is not desired. |
|
* |
|
* @return {String[][]} An array of rows where each row is an array of Strings. |
|
*/ |
|
decode: function (input, delimiter) { |
|
var me = this, |
|
// Check to see if the column delimiter is defined. If not, |
|
// then default to comma. |
|
delim = (delimiter || me.delimiter), |
|
row = [], |
|
result = [row], |
|
quote = me.quote, |
|
quoteREs = me.quoteREs, |
|
parseREs = me.parseREs, |
|
|
|
// Create a regular expression to parse the CSV values unless we already have |
|
// one for this delimiter. |
|
parseRE = parseREs[delim] || |
|
(parseREs[delim] = new RegExp( |
|
// Delimiters. |
|
"(\\" + delim + "|\\r?\\n|\\r|^)" + |
|
|
|
// Quoted fields. |
|
"(?:\\" + quote + "([^\\" + quote + "]*(?:\\" + quote + "\\" + quote + |
|
"[^\\" + quote + "]*)*)\\" + quote + "|" + |
|
|
|
// Standard fields. |
|
"([^\"\\" + delim + "\\r\\n]*))", |
|
"gi")), |
|
|
|
dblQuoteRE = quoteREs[quote] || |
|
(quoteREs[quote] = new RegExp('\\' + quote + '\\' + quote, 'g')), |
|
|
|
arrMatches, strMatchedDelimiter, strMatchedValue; |
|
|
|
// Keep looping over the regular expression matches |
|
// until we can no longer find a match. |
|
while (arrMatches = parseRE.exec(input)) { |
|
strMatchedDelimiter = arrMatches[1]; |
|
|
|
// Check to see if the given delimiter has a length |
|
// (is not the start of string) and if it matches |
|
// field delimiter. If id does not, then we know |
|
// that this delimiter is a row delimiter. |
|
if (strMatchedDelimiter.length && strMatchedDelimiter !== delim) { |
|
// Since we have reached a new row of data, |
|
// add an empty row to our data array. |
|
result.push(row = []); |
|
} |
|
|
|
// Now that we have our delimiter out of the way, |
|
// let's check to see which kind of value we |
|
// captured (quoted or unquoted). |
|
if (arrMatches[2]) { |
|
// We found a quoted value. When we capture |
|
// this value, unescape any double quotes. |
|
strMatchedValue = arrMatches[2].replace(dblQuoteRE, '"'); |
|
} else { |
|
// We found a non-quoted value. |
|
strMatchedValue = arrMatches[3]; |
|
} |
|
|
|
row.push(strMatchedValue); |
|
} |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Converts a two-dimensional array into an encoded string. |
|
* |
|
* For example: |
|
* |
|
* Ext.util.CSV.encode([ |
|
* ['foo "bar", bletch', 'Normal String', new Date()], |
|
* [Math.PI, 1, false] |
|
* ]); |
|
* |
|
* The above produces the following string: |
|
* |
|
* '"foo ""bar"", bletch",Normal String,2010-01-01T21:45:32.004Z\u000a3.141592653589793,1,false' |
|
* |
|
* @param {Mixed[][]} input An array of row data arrays. |
|
* |
|
* @param {String} [delimiter] The column delimiter to use if the default value |
|
* of {@link #cfg-delimiter delimiter} is not desired. |
|
* |
|
* @return {String} A string in which data items are separated by {@link #delimiter} |
|
* characters, and rows are separated by {@link #lineBreak} characters. |
|
*/ |
|
encode: function (input, delimiter) { |
|
var me = this, |
|
delim = delimiter || me.delimiter, |
|
dateFormat = me.dateFormat, |
|
quote = me.quote, |
|
twoQuotes = quote + quote, |
|
rowIndex = input.length, |
|
lineBreakRe = me.lineBreakRe, |
|
result = [], |
|
outputRow = [], |
|
col, columnIndex, inputRow; |
|
|
|
while (rowIndex-- > 0) { |
|
inputRow = input[rowIndex]; |
|
outputRow.length = columnIndex = inputRow.length; |
|
|
|
while (columnIndex-- > 0) { |
|
col = inputRow[columnIndex]; |
|
|
|
if (col == null) { // == null || === undefined |
|
col = ''; |
|
} else if (typeof col === 'string') { |
|
if (col) { |
|
// If the value contains quotes, double them up, and wrap with quotes |
|
if (col.indexOf(quote) > -1) { |
|
col = quote + col.split(quote).join(twoQuotes) + quote; |
|
} else if (col.indexOf(delim) > -1 || lineBreakRe.test(col)) { |
|
col = quote + col + quote; |
|
} |
|
} |
|
} else if (Ext.isDate(col)) { |
|
col = Ext.Date.format(col, dateFormat); |
|
} |
|
//<debug> |
|
else if (col && (isNaN(col) || Ext.isArray(col))) { |
|
Ext.Error.raise('Cannot serialize ' + Ext.typeOf(col) + ' into CSV'); |
|
} |
|
//</debug> |
|
|
|
outputRow[columnIndex] = col; |
|
} |
|
|
|
result[rowIndex] = outputRow.join(delim); |
|
} |
|
|
|
return result.join(me.lineBreak); |
|
} |
|
});
|
|
|