Tho*_*mas 8 text-processing csv
我的输入文件是:
$ cat -e myfile.txt
999a bcd efgh555$
8 z 7 $
1 xx xx xx 48 $
Run Code Online (Sandbox Code Playgroud)
我需要一个列中没有尾随空格的 CSV:
999,a bcd efgh,555
8,z,7
1,xx xx xx,48
Run Code Online (Sandbox Code Playgroud)
到目前为止,我成功地在需要的地方添加了昏迷:
$ gawk '$1=$1' FIELDWIDTHS="3 10 3" OFS=, myfile.txt
999,a bcd efgh,555
8 ,z ,7
1 ,xx xx xx ,48
Run Code Online (Sandbox Code Playgroud)
我怎样才能删除尾随空格?
编辑:数据中可能已经有逗号,所以我需要:(i)将字段用双引号括起来,(ii)使用\"(或""根据RFC 4180)转义字段中可能已经存在的双引号。例如,a,aab"bbccc-> "a,aa","b\"bb","ccc"。
gawk(不仅awk)perl)。gawk ... | sed ...),因为我有很多大文件要处理。FIELDWIDTHS自动计算。和perl:
<your-file perl -C -lnse 'print map {s/\\s+$//r} unpack "a3a10a3"' -- -,=,\nRun Code Online (Sandbox Code Playgroud)\nunpack()进行相当于 gawk 的FIELDWIDTHS处理。
$,,此处与 awk 的等效项OFS设置为,with -,=,where-s导致-var=value参数被理解为分配value给$var。或者,您可以省略-s, 并BEGIN{$, = ","}在开头添加一条语句,就像BEGIN{OFS = ","}在 awk 中代替 一样-v OFS=,。
-C如果区域设置使用 UTF-8 作为其字符映射,则将输入视为 UTF-8 编码,忽略具有不同多字节字符映射的区域设置,因为这些天几乎从未使用过这些区域设置。
如果要修剪的空格字符都是 ASCII 字符,正如您所发现的,可以通过使用A说明符来进一步简化,而不是a删除unpack()尾随 ASCII 空格(和 NUL):
<your-file perl -C -lnse 'print unpack "A3A10A3"' -- -,=,\nRun Code Online (Sandbox Code Playgroud)\n这是根据字符数来考虑宽度的。
\n对于字节数,请删除-C.
对于字素簇的数量,您可以替换unpack "a3a10a3"为/^(\\X{3})(\\X{10})(\\X{3})/。
对于显示宽度,考虑到每个字符的宽度(包括零宽、单宽和双宽,但不支持 TAB\xc2\xb9、CR...等控制字符),在 中,zsh可以做:
widths=(3 10 3)\nwhile IFS= read -ru3 line; do\n csv=()\n for width in $widths; do\n field=${(mr[width])line}\n line=${line#$field}\n csv+=("${(M)field##*[^[:space:]]}")\n done\n print -r -- ${(j[,])csv}\ndone 3< your-file\nRun Code Online (Sandbox Code Playgroud)\n在r[width] right-pad 并将文本截断为给定宽度的情况下,m这是根据显示宽度而不是字符数来完成的,并${(M)field##*[^[:space:]]}扩展到与模式相关的前导部分,$field这M就是直到最后一个非-whitespace (${field%%[[:space:]]#}与不需要相同set -o extendedglob)。
这可能会比 慢很多perl。
如果您的文件仅包含 ASCII 文本(如示例中所示),则它们应该都是等效的。然后删除-Cfor或将perl区域设置设置为C/ POSIXfor sed//可能会提高性能。gawkperl
在 UTF-8 语言环境中,输入重复 100000 次,这里我得到 1.1 秒perl(变体为 0.34 A,变体为 1.7 \\X),Paul 的为 1.3 秒gawk,zsh 为 31 秒,GNU sed 's/./&,/13;s/./&,/3;s/[[:space:]]*,/,/g;s/[[:space:]]*$//'(标准)为 2.1 秒,1.1 为sed -E 's/^(.{3})(.{10})/\\1,\\2,/;s/\\s+,/,/g;s/\\s+$//'(非标准)。
在 C 语言环境中,分别变为 0.9 (0.27, 1.2)、0.7、31、1.3、0.5。
\n这些假设字段不包含,或"字符。某些 CSV 格式还需要引用带有前导或尾随空格的字段。
要创建正确的 CSV 输出,最简单的方法是使用以下Text::CSV模块perl:
<your-file perl -C -MText::CSV -lne '\n BEGIN{$csv = Text::CSV->new({binary => 1})}\n $csv->print(*STDOUT, [unpack "A3A10A3"])'\nRun Code Online (Sandbox Code Playgroud)\n默认情况下,
\n,"...""""在引号内转义但这些可以在new()调用中进行调整。perldoc Text::CSV详情请参阅。
\xc2\xb9 虽然对于 TAB 特别而言,您可以预处理输入以expand将这些 TAB 转换为空格序列;对于其他的,宽度的概念通常很难适用,并且取决于文本发送到的显示设备。
$ cat txx
9 a bcd 55 # <- 1 trailing space here
48 z 7 # <- 2 trailing spaces here
1 xx xx xx 489
aaabbb bb bccchh
$ awk 'BEGIN { FIELDWIDTHS="3 10 3"; OFS=","; }
{ for (f = 1; f <= NF; ++f) sub (/[[:space:]]*$/, "", $f); print; }' txx
9,a bcd,55
48,z,7
1,xx xx xx,489
aaa,bbb bb b,ccc
Run Code Online (Sandbox Code Playgroud)