我想在处理 CSV 文件之前检查它的列数。问题是分隔符(逗号)也出现在某些字段的文本中,因此我无法正确解析它并且收到太多列。
例如:
~new file: 12345~,~125.5~,,,~ example (45), case (20)~,,
7 列
~new file: 12345~
~125.5~
- 空的
- 空的
~ example (45), case (20)~
- 空的
- 空的
问题是第五~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
解释