【发布时间】:2020-03-24 06:37:18
【问题描述】:
在 UNIX 命令行上,我们可以使用简单的字段分隔符(或字段分隔符)来执行简单的面向记录的文件工作。常见的分隔符是空格、制表符或竖线,但任何字符都可以作为分隔符。命令sort、join、cut等都将字段分隔符作为选项-t或-d,并且shell(再次bourne或bourne)接受read -a命令的IFS环境变量将一行解析为一个数组或set -- 命令将一行解析为特殊的命令行参数变量$0, $1, ....
简单的字段分隔符方法很简单,唯一需要注意的是分隔符字符不会出现在数据本身中。理想情况下根本没有。这可以适用于特定的数据集,但不能普遍适用。这就是为什么在 UNIX shell 和 C 语言(以及从那里开始的 C++、Java)上,反斜杠转义序列有时用于将此类分隔符标记为数据的一部分(典型的 \_,例如,当您有一个带有空格的文件名时. 但是,记录和面向字段的命令(例如排序、剪切和连接)不支持任何方式。
现在,我们通常会下载“逗号分隔值”(CSV) 文件,这种格式显然源自 Windows 世界。其中逗号用作分隔符(通常是一个不好的选择,因为逗号很可能出现在实际数据值中),并且如果数据字段可能包含逗号(甚至空格)。然后在这样的引用值中,如果引用是值的一部分,则通过将其加倍 "" 将其“转义”。
现在我正在寻找将 CSV 文件转换为简单分隔文件的最简单方法。可以选择数据中未出现的任何分隔符。
难点在于 CSV 引用规则需要一个非常简单的有状态解析器。你要么在引用值之内,要么在引用值之外。如果在里面,你需要阅读重复的引用""作为引用。
我在这里找不到最佳答案,在一般的互联网搜索中我发现了一些东西,但它们不正确或使用了太多工具。
让我们把它变成一场比赛。在 bourne shell 或 bash 上仅使用 sed(可能还有 grep 和 tr)运行的最简单和优雅的单行程序赢得了公认的答案。如果结果更优雅并且不依赖于 AWK 的一个特殊版本,则允许使用 AWK。不允许使用 Perl,也不允许使用 C 程序。
我当然会尝试自己的答案。
更新: 那些甚至不用 sed 并直接转向 awk 的人显然具有优势。如果有人可以在 sed 中优雅地做到这一点,他们将是赢家。我自己在 sed 中的尝试并不优雅。
我发现 CSV 文件可能在带引号的字段中包含换行符。这是需要考虑的。由于我们正在尝试为 UNIX shell 处理创建简单的记录和字段格式,因此这些嵌入的换行符应转换为 \n。
PS:有人问:为什么是“单线”。它不一定是严格意义上的单行,重点在于您可以在命令行上创建它。为什么不是 Perl?因为大多数 UNIX 系统都带有 shell 和 sed 和 awk,但是需要安装 Perl(并且有所有这些不同的版本),对于 Python 来说相同或更糟。在我使用 Perl 或 Python 之前,我只会用 C 编写它。不,我们不想要任何语言,它应该在基本的 UNIX 设置上运行,而不需要安装一堆东西。
【问题讨论】:
-
CSV 是非正式的,即。不是标准化的格式。例如,引号可能因此被转义:
"value \"quoted\""。另一个例子:一些解析器可能要求逗号之间为空值(value,,value),但其他解析器完全省略它们(value,value)。您的问题格式可能更适合 CodeGolf,他们经常参加此类比赛。 -
这与 stackoverflow 上已经存在的许多其他“使用 sed 解析 csv”问题有何不同?如果 CSV 文件已经包含所有可能的字符,您建议如何选择分隔符?
-
@rath CSV 可能是非正式的,但许多公共数据发布都包含在 CSV 文件中。我从来没有在它们中看到反斜杠转义。,省略空字段显然被破坏了。我同意周围有许多损坏的 CSV 文件方法(因此是我的问题),但是有一种方法可以区分好坏,我们不必担心坏的损坏的 CSV 文件或解析器。如果你愿意的话,“黄金标准”是“你能在 Excel 中打开它吗”?
-
@jhnc 我以前在这里搜索过。如果您在 stackoverflow 上有一个“使用 sed 解析 csv”,欢迎您指出。我找不到任何东西。如果需要,请将此问题标记为重复。
-
为了公平起见,将所有
awk-ers 放在同一基线上:gnu.org/software/gawk/manual/html_node/…
标签: shell csv parsing unix sed