列的字段分隔符部分 - 错误解析 unix

列的字段分隔符部分 - 错误解析 unix

我想在处理 CSV 文件之前检查它的列数。问题是分隔符(逗号)也出现在某些字段的文本中,因此我无法正确解析它并且收到太多列。

例如:

~new file: 12345~,~125.5~,,,~ example (45), case (20)~,,

7 列

  1. ~new file: 12345~
  2. ~125.5~
  3. 空的
  4. 空的
  5. ~ example (45), case (20)~
  6. 空的
  7. 空的

问题是第五~example (45), case (20)~列中的逗号。

,我尝试用;using替换分隔符sed,但我必须进行多次迭代。

我想要一个通用规则,能够以更优化的方法匹配多个案例。

请注意~是一个字段引用字符(a, b, c, d四个字段也是如此,但a, ~b, c~, d是三个字段,其中之一是b, c)。

样本:

~new file: 12345~,~125.5~,,,~ example (45), case (20)~,,
~file (54) ~,,~5.5~,,~ this is a sample.~,,~end, end~
~line 3~,~3.6~,~0.0~,~hello~,~hello, world~,~6.7~,~end of line~

预期输出:

~new file: 12345~;~125.5~;;;~ example (45), case (20)~;;
~file (54) ~;;~5.5~;;~ this is a sample.~;;~end, end~
~line 3~;~3.6~;~0.0~;~hello~;~hello, world~;~6.7~;~end of line~

答案1

这看起来像一个 CSV 文件,使用逗号作为字段分隔符,使用波浪号作为引用字符。

使用正确的 CSV 解析器,例如 Perl 模块提供的解析器Text::CSV

perl -MText::CSV -e 'print scalar(@{Text::CSV->new({quote_char=>"~"})->getline(\*STDIN)})' <file.csv

这将读取 CSV 文件的第一行file.csv并打印其中的列数。我们实例化一个解析器,在使用该解析器读取第一行之前,该解析器了解引号字符是波浪号。该解析器上的方法getline()将从给定的文件句柄中读取一行并返回对数据数组的引用,每个解析的列一个项目。这print scalar(...)是在 Perl 中打印数组长度的一种相当常见的方法。

另一种方法是使用CSV套件命令行 CSV 解析器工具包:

csvstat -n -q '~' <file.csv | wc -l

或者等效地,使用长选项,

csvstat --names --quotechar '~' <file.csv | wc -l

这同样会读取输入文件的第一行并返回标题列表(CSV 文件的第一行通常包含列标题),每行一个。计算wc -l返回的行数。

命令csvstat本身(不带wc -l)将返回

  1: new file: 12345
  2: 125.5
  3:
  4:
  5:  example (45), case (20)
  6:
  7:

当您稍后解析 CSV 文件时,我建议您使用其中一种方法,或者使用您最习惯的编程语言寻找合适的解析器。awk并可sed用于简单的CSV 数据,但在这种情况下,您的数据使用了一些 CSV 格式功能,如果不小心的话,这些工具将很难处理这些功能。

答案2

回答修改后的问题:

sed -r 's/(~[^~]*~)?,/\1;/g' infile
~new file: 12345~;~125.5~;;;~ example (45), case (20)~;;
~file (54) ~;;~5.5~;;~ this is a sample.~;;~end; end~
~line 3~;~3.6~;~0.0~;~hello~;~hello, world~;~6.7~;~end of line~

将 all 替换~...~,~...~;where~...~可以是可选的。


要计算每行中的列数,awk您可以这样做:

awk -F, '{ gsub(/~[^~]*~/,""); print NF }' infile

对于这样的输入:

~new file: 12345~,~125.5~,,,~ example (45), case (20)~,,
,~125.5~,,,~ example (45), case (20)~

它将返回:

7
5

在 中,我们将从 a 开始直到下一个 看到的每个模式(例如)gsub(/~[^~]*~/,"")替换为空字符串;见下文:~~~...~

awk -F, '{ gsub(/~[^~]*~/,""); print $0 }' infile
,,,,,,
,,,,

这假设您的输入中没有内部~类似。,~some~thing~,

然后print NF将根据指定的字段分隔符打印字段数-F

答案3

,是列分隔符...我只需运行命令column如下:

column -s',' -t -o',' original_data.txt > output.csv

解释

相关内容