d3-dsv
此模块提供了用于分隔符分隔值的解析器和格式化器,最常见的是逗号分隔值 (CSV) 或制表符分隔值 (TSV)。这些表格格式在像 Microsoft Excel 这样的电子表格程序中很受欢迎,并且通常比 JSON 更节省空间。此实现基于RFC 4180。
🌐 This module provides a parser and formatter for delimiter-separated values, most commonly comma-separated values (CSV) or tab-separated values (TSV). These tabular formats are popular with spreadsheet programs such as Microsoft Excel, and are often more space-efficient than JSON. This implementation is based on RFC 4180.
例如,解析:
🌐 For example, to parse:
d3.csvParse("foo,bar\n1,2") // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]d3.tsvParse("foo\tbar\n1\t2") // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]格式化:
🌐 To format:
d3.csvFormat([{foo: "1", bar: "2"}]) // "foo,bar\n1,2"d3.tsvFormat([{foo: "1", bar: "2"}]) // "foo\tbar\n1\t2"要使用不同的分隔符,例如用于管道分隔值的“|”,请使用 d3.dsvFormat:
🌐 To use a different delimiter, such as “|” for pipe-separated values, use d3.dsvFormat:
d3.dsvFormat("|").parse("foo|bar\n1|2")) // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]要在浏览器中轻松加载 DSV 文件,请参阅 d3-fetch 的 d3.csv、d3.tsv 和 d3.dsv 方法。
🌐 For easy loading of DSV files in a browser, see d3-fetch’s d3.csv, d3.tsv and d3.dsv methods.
dsvFormat(分隔符)
🌐 dsvFormat(delimiter)
const csv = d3.dsvFormat(",");来源 · 为指定的分隔符构建一个新的DSV解析器和格式化器。分隔符必须是一个单字符(即,单个16位码单元);因此,ASCII分隔符是可以的,但表情符号分隔符则不行。
dsv.parse(string, row)
小心
此方法需要使用 unsafe-eval 内容安全策略。
d3.csvParse("foo,bar\n1,2") // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]来源 · 解析指定的字符串,该字符串必须采用适当分隔符的分隔值格式,返回表示解析行的对象数组。
与 dsv.parseRows 不同,这种方法要求 DSV 内容的第一行包含由分隔符分隔的列名列表;这些列名将成为返回对象的属性。例如,考虑以下 CSV 文件:
🌐 Unlike dsv.parseRows, this method requires that the first line of the DSV content contains a delimiter-separated list of column names; these column names become the attributes on the returned objects. For example, consider the following CSV file:
Year,Make,Model,Length
1997,Ford,E350,2.34
2000,Mercury,Cougar,2.38生成的 JavaScript 数组为:
🌐 The resulting JavaScript array is:
[
{"Year": "1997", "Make": "Ford", "Model": "E350", "Length": "2.34"},
{"Year": "2000", "Make": "Mercury", "Model": "Cougar", "Length": "2.38"}
]返回的数组还会暴露一个 columns 属性,其中包含按输入顺序排列的列名(与 Object.keys 不同,其迭代顺序是任意的)。例如:
🌐 The returned array also exposes a columns property containing the column names in input order (in contrast to Object.keys, whose iteration order is arbitrary). For example:
data.columns // ["Year", "Make", "Model", "Length"]如果列名不唯一,则每个名称只返回最后一个值;要访问所有值,请改用 dsv.parseRows(参见 示例)。
🌐 If the column names are not unique, only the last value is returned for each name; to access all values, use dsv.parseRows instead (see example).
如果未指定行转换函数,字段值将是字符串。为了安全起见,不会自动转换为数字、日期或其他类型。在某些情况下,JavaScript可能会自动将字符串强制转换为数字(例如,使用+运算符),但更好的做法是指定一个行转换函数。有关方便的行转换函数,它可以推断并强制转换常见类型如数字和字符串,请参见d3.autoType。
🌐 If a row conversion function is not specified, field values are strings. For safety, there is no automatic conversion to numbers, dates, or other types. In some cases, JavaScript may coerce strings to numbers for you automatically (for example, using the + operator), but better is to specify a row conversion function. See d3.autoType for a convenient row conversion function that infers and coerces common types like numbers and strings.
如果指定了 row 转换函数,则对每一行都会调用指定的函数,该函数会传入表示当前行的对象(d)、从零开始计数的索引(i,对于第一个非表头行为零)以及列名数组。如果返回值为 null 或 undefined,则跳过该行,并且该行不会包含在 dsv.parse 返回的数组中;否则,返回值将定义对应的行对象。例如:
🌐 If a row conversion function is specified, the specified function is invoked for each row, being passed an object representing the current row (d), the index (i) starting at zero for the first non-header row, and the array of column names. If the returned value is null or undefined, the row is skipped and will be omitted from the array returned by dsv.parse; otherwise, the returned value defines the corresponding row object. For example:
const data = d3.csvParse(string, (d) => {
return {
year: new Date(+d.Year, 0, 1), // lowercase and convert "Year" to Date
make: d.Make, // lowercase
model: d.Model, // lowercase
length: +d.Length // lowercase and convert "Length" to number
};
});注意:使用 + 或 Number 而不是 parseInt 或 parseFloat 通常更快,但限制更多。例如,"30px" 在使用 + 强制转换时返回 NaN,而 parseInt 和 parseFloat 返回 30。
🌐 Note: using + or Number rather than parseInt or parseFloat is typically faster, though more restrictive. For example, "30px" when coerced using + returns NaN, while parseInt and parseFloat return 30.
dsv.parseRows(string, row)
d3.csvParseRows("foo,bar\n1,2") // [["foo", "bar"], ["1", "2"]]来源 · 解析指定的字符串,该字符串必须采用适当分隔符的分隔值格式,返回表示解析行的数组的数组。
与 dsv.parse 不同,此方法将标题行视为标准行,并且应在 DSV 内容不包含标题时使用。每行表示为数组而不是对象。行的长度可能不同。例如,考虑下面的 CSV 文件,其中显然缺少标题行:
🌐 Unlike dsv.parse, this method treats the header line as a standard row, and should be used whenever DSV content does not contain a header. Each row is represented as an array rather than an object. Rows may have variable length. For example, consider the following CSV file, which notably lacks a header line:
1997,Ford,E350,2.34
2000,Mercury,Cougar,2.38生成的 JavaScript 数组为:
🌐 The resulting JavaScript array is:
[
["1997", "Ford", "E350", "2.34"],
["2000", "Mercury", "Cougar", "2.38"]
]如果未指定行转换函数,字段值将是字符串。为了安全起见,不会自动转换为数字、日期或其他类型。在某些情况下,JavaScript可能会自动将字符串强制转换为数字(例如,使用+运算符),但更好的做法是指定一个行转换函数。有关方便的行转换函数,它可以推断并强制转换常见类型如数字和字符串,请参见d3.autoType。
🌐 If a row conversion function is not specified, field values are strings. For safety, there is no automatic conversion to numbers, dates, or other types. In some cases, JavaScript may coerce strings to numbers for you automatically (for example, using the + operator), but better is to specify a row conversion function. See d3.autoType for a convenient row conversion function that infers and coerces common types like numbers and strings.
如果指定了row转换函数,将对每一行调用指定的函数,并传入表示当前行的数组(d)、从零开始的行索引(i)以及列名数组。如果返回值为 null 或 undefined,则该行将被跳过,并从 dsv.parse 返回的数组中省略;否则,返回值定义对应的行对象。例如:
🌐 If a row conversion function is specified, the specified function is invoked for each row, being passed an array representing the current row (d), the index (i) starting at zero for the first row, and the array of column names. If the returned value is null or undefined, the row is skipped and will be omitted from the array returned by dsv.parse; otherwise, the returned value defines the corresponding row object. For example:
const data = d3.csvParseRows(string, (d, i) => {
return {
year: new Date(+d[0], 0, 1), // convert first column to Date
make: d[1],
model: d[2],
length: +d[3] // convert fourth column to number
};
});实际上,row 类似于对返回的行应用 map 和 filter 操作符。
🌐 In effect, row is similar to applying a map and filter operator to the returned rows.
dsv.format(rows, columns)
d3.csvFormat([{foo: "1", bar: "2"}]) // "foo,bar\n1,2"d3.csvFormat([{foo: "1", bar: "2"}], ["foo"]) // "foo\n1"Source · 将指定的对象数组 rows 格式化为分隔符分隔的值,返回一个字符串。此操作是 dsv.parse 的逆操作。每一行将用换行符 (\n) 分隔,每行中的每一列将用分隔符(例如逗号,,)分隔。包含分隔符、双引号 (") 或换行符的值将使用双引号进行转义。
如果未指定 columns,则形成表头行的列名列表由 rows 中所有对象的所有属性的并集确定;列的顺序是非确定性的。如果指定了 columns,它是一个表示列名的字符串数组。例如:
🌐 If columns is not specified, the list of column names that forms the header row is determined by the union of all properties on all objects in rows; the order of columns is nondeterministic. If columns is specified, it is an array of strings representing the column names. For example:
const string = d3.csvFormat(data, ["year", "make", "model", "length"]);每个行对象上的所有字段都会被强制转换为字符串。如果字段值为 null 或 undefined,则使用空字符串。如果字段值是日期,则使用 ECMAScript 日期时间字符串格式(ISO 8601 的子集):例如,UTC 午夜的日期格式为 YYYY-MM-DD。要更好地控制哪些字段以及如何格式化字段,首先将 rows 映射为字符串数组的数组,然后使用 dsv.formatRows。
🌐 All fields on each row object will be coerced to strings. If the field value is null or undefined, the empty string is used. If the field value is a Date, the ECMAScript date-time string format (a subset of ISO 8601) is used: for example, dates at UTC midnight are formatted as YYYY-MM-DD. For more control over which and how fields are formatted, first map rows to an array of array of string, and then use dsv.formatRows.
dsv.formatBody(rows, columns)
d3.csvFormatBody([{foo: "1", bar: "2"}]) // "1,2"d3.csvFormatBody([{foo: "1", bar: "2"}], ["foo"]) // "1"来源 · 等同于 dsv.format,但省略了标题行。例如,这在向现有文件追加行时非常有用。
dsv.formatRows(rows)
d3.csvFormatRows([["foo", "bar"], ["1", "2"]]) // "foo,bar\n1,2"来源 · 将指定的字符串数组数组 rows 格式化为分隔符分隔的值,返回一个字符串。此操作是 dsv.parseRows 的逆操作。每一行将由换行符 (\n) 分隔,每行中的每一列将由分隔符(例如逗号,,)分隔。包含分隔符、双引号 (") 或换行符的值将使用双引号进行转义。
要将对象数组转换为数组数组,同时明确指定列,请使用 array.map。例如:
🌐 To convert an array of objects to an array of arrays while explicitly specifying the columns, use array.map. For example:
const string = d3.csvFormatRows(data.map((d, i) => {
return [
d.year.getUTCFullYear(), // Assuming d.year is a Date object.
d.make,
d.model,
d.length
];
}));如果你愿意,你也可以用列名数组通过 array.concat 将这个结果合并,以生成第一行:
🌐 If you like, you can also array.concat this result with an array of column names to generate the first row:
const string = d3.csvFormatRows([[
"year",
"make",
"model",
"length"
]].concat(data.map((d, i) => {
return [
d.year.getUTCFullYear(), // Assuming d.year is a Date object.
d.make,
d.model,
d.length
];
})));dsv.formatRow(row)
d3.csvFormatRow(["foo", "bar"]) // "foo,bar"来源 · 将单个字符串数组行格式化为分隔符分隔的值,返回一个字符串。行内的每一列将由分隔符(例如逗号 ,)分隔。包含分隔符、双引号(")或换行符的值将使用双引号进行转义。
dsv.formatValue(value)
d3.csvFormatValue("foo") // "foo"来源 · 将单个值或字符串格式化为分隔符分隔的值,返回一个字符串。包含分隔符、双引号 (") 或换行符的值将使用双引号进行转义。
csv解析(string, row)
🌐 csvParse(string, row)
🌐 Equivalent to d3.dsvFormat(",").parse.
csvParseRows(字符串, 行)
🌐 csvParseRows(string, row)
等同于 d3.dsvFormat(",").parseRows。
🌐 Equivalent to d3.dsvFormat(",").parseRows.
csvFormat(行, 列)
🌐 csvFormat(rows, columns)
🌐 Equivalent to d3.dsvFormat(",").format.
csvFormatBody(行, 列)
🌐 csvFormatBody(rows, columns)
等同于 d3.dsvFormat(",").formatBody。
🌐 Equivalent to d3.dsvFormat(",").formatBody.
csvFormatRows(rows)
等同于 d3.dsvFormat(",").formatRows。
🌐 Equivalent to d3.dsvFormat(",").formatRows.
csvFormatRow(row)
等同于 d3.dsvFormat(",").formatRow。
🌐 Equivalent to d3.dsvFormat(",").formatRow.
csvFormatValue(value)
等同于 d3.dsvFormat(",").formatValue。
🌐 Equivalent to d3.dsvFormat(",").formatValue.
tsvParse(字符串, 行)
🌐 tsvParse(string, row)
🌐 Equivalent to d3.dsvFormat("\t").parse.
tsvParseRows(string, row)
等同于 d3.dsvFormat("\t").parseRows。
🌐 Equivalent to d3.dsvFormat("\t").parseRows.
tsvFormat(行, 列)
🌐 tsvFormat(rows, columns)
等同于 d3.dsvFormat("\t").format。
🌐 Equivalent to d3.dsvFormat("\t").format.
tsvFormatBody(rows, columns)
等同于 d3.dsvFormat("\t").formatBody。
🌐 Equivalent to d3.dsvFormat("\t").formatBody.
tsvFormatRows(rows)
等同于 d3.dsvFormat("\t").formatRows。
🌐 Equivalent to d3.dsvFormat("\t").formatRows.
tsvFormatRow(row)
等同于 d3.dsvFormat("\t").formatRow。
🌐 Equivalent to d3.dsvFormat("\t").formatRow.
tsvFormatValue(value)
等同于 d3.dsvFormat("\t").formatValue。
🌐 Equivalent to d3.dsvFormat("\t").formatValue.
自动类型(object)
🌐 autoType(object)
来源 · 给定一个表示已解析行的对象(或数组),推断对象中值的类型并相应地进行转换,返回被修改的对象。此函数旨在作为行访问器函数,与dsv.parse和dsv.parseRows结合使用。例如,考虑以下CSV文件:
Year,Make,Model,Length
1997,Ford,E350,2.34
2000,Mercury,Cougar,2.38当与 d3.csvParse 一起使用时,
🌐 When used with d3.csvParse,
d3.csvParse(string, d3.autoType)生成的 JavaScript 数组为:
🌐 the resulting JavaScript array is:
[
{"Year": 1997, "Make": "Ford", "Model": "E350", "Length": 2.34},
{"Year": 2000, "Make": "Mercury", "Model": "Cougar", "Length": 2.38}
]类型推断的工作原理如下。对于给定对象中的每个值,计算修剪后的值;然后按如下方式重新赋值:
🌐 Type inference works as follows. For each value in the given object, the trimmed value is computed; the value is then re-assigned as follows:
- 如果为空,则为
null。 - 如果恰好是
"true",那么true。 - 如果恰好是
"false",那么false。 - 如果恰好是
"NaN",那么NaN。 - 否则,如果可以被强制转换为数字(https://www.ecma-international.org/ecma-262/9.0/index.html#sec-tonumber-applied-to-the-string-type),则为数字。
- 否则,如果是 仅日期或日期-时间字符串,则为日期。
- 否则,返回一个字符串(未修剪的原始值)。
带前导零的值可能会被强制转换为数字;例如 "08904" 会被强制转换为 8904。然而,额外的字符例如逗号或单位(例如 "$1.00"、"(123)"、"1,234" 或 "32px")会阻止数字强制转换,从而导致结果为字符串。
🌐 Values with leading zeroes may be coerced to numbers; for example "08904" coerces to 8904. However, extra characters such as commas or units (e.g., "$1.00", "(123)", "1,234" or "32px") will prevent number coercion, resulting in a string.
日期字符串必须符合 ECMAScript 的 ISO 8601 格式 子集。当指定仅日期字符串(例如 YYYY-MM-DD)时,推断的时间为 UTC 午夜;然而,如果指定例如 YYYY-MM-DDTHH:MM 的日期时间字符串而未提供时区,则假定为本地时间。
🌐 Date strings must be in ECMAScript’s subset of the ISO 8601 format. When a date-only string such as YYYY-MM-DD is specified, the inferred time is midnight UTC; however, if a date-time string such as YYYY-MM-DDTHH:MM is specified without a time zone, it is assumed to be local time.
自动类型推断主要旨在在与 dsv.format 和 dsv.formatRows 配合使用时,为常见的 JavaScript 类型提供安全、可预测的行为。如果你需要不同的行为,你应该实现自己的行访问函数。
🌐 Automatic type inference is primarily intended to provide safe, predictable behavior in conjunction with dsv.format and dsv.formatRows for common JavaScript types. If you need different behavior, you should implement your own row accessor function.
更多内容,请参见 d3.autoType 注意本。
🌐 For more, see the d3.autoType notebook.
内容安全策略
🌐 Content security policy
如果存在 内容安全策略,请注意 dsv.parse 在 script-src 指令中需要 unsafe-eval,这是由于为了快速解析而(安全地)使用动态代码生成。(参见 源代码。)或者,可以使用 dsv.parseRows。
🌐 If a content security policy is in place, note that dsv.parse requires unsafe-eval in the script-src directive, due to the (safe) use of dynamic code generation for fast parsing. (See source.) Alternatively, use dsv.parseRows.
字节顺序标记
🌐 Byte-order marks
DSV 文件有时以 字节顺序标记 (BOM) 开头;例如,从 Microsoft Excel 中将电子表格保存为 CSV UTF-8 格式时,会包含 BOM。在网络上,这通常不是问题,因为编码标准中指定的 UTF-8 解码算法 会移除 BOM。另一方面,Node.js 在解码 UTF-8 时 不会移除 BOM。
🌐 DSV files sometimes begin with a byte order mark (BOM); saving a spreadsheet in CSV UTF-8 format from Microsoft Excel, for example, will include a BOM. On the web this is not usually a problem because the UTF-8 decode algorithm specified in the Encoding standard removes the BOM. Node.js, on the other hand, does not remove the BOM when decoding UTF-8.
如果不移除 BOM,文本的第一个字符是零宽不间断空格。因此,如果带有 BOM 的 CSV 文件被 d3.csvParse 解析,第一个列的名称将以零宽不间断空格开头。由于打印时这个字符通常不可见,这可能很难察觉。
🌐 If the BOM is not removed, the first character of the text is a zero-width non-breaking space. So if a CSV file with a BOM is parsed by d3.csvParse, the first column’s name will begin with a zero-width non-breaking space. This can be hard to spot since this character is usually invisible when printed.
在解析之前要移除 BOM,可以考虑使用 strip-bom。
🌐 To remove the BOM before parsing, consider using strip-bom.