我有两个 sed 命令,当从命令行对 csv 文件单独执行时,它们工作得非常好。它们都旨在修复 csv 文件列之一中的小数格式并将小数四舍五入为两位。
- 这个在只有一位小数的数字上加 0:
sed -r -e 's/[0-9]\;[0-9]+\.[0-9]/&0/'
- 将小数点后两位以上的数字四舍五入:
sed -re 's/([0-9]+\.[0-9]{2})[0-9]+/\1/'
现在我想将它们放在一个 sed 脚本中,以便能够同时应用它们。我创建了这个名为fixed_floats.sed的脚本
#!/bin/sed
s/[0-9]\;[0-9]+\.[0-9]/&0/
s/(\[0-9]+\.[0-9]{2}\)[0-9]+/\1/
当我尝试使用以下命令执行它时:
sed -f fix_floats.sed titanic-passengers.csv
输出没有出现任何变化(sed命令中的正则表达式被扩展,所以我认为它不起作用的原因是我在执行脚本时没有指定它)
当我尝试使用以下命令执行它时:
sed -E -f fix_floats.sed titanic-passengers.csv
我收到以下错误:
sed: file fix_floats.sed line 5: invalid reference \1 on `s' command's RHS
关于如何创建具有扩展正则表达式的 sed 脚本以便能够有效地将其应用于 csv 有什么建议吗?
原始输出:(感兴趣的列是行末尾的第三列)
356;No;3;Vanden Steen, Mr. Leo Peter;male;28.0;0;0;345783;9.5;;S
546;No;1;Nicholson, Mr. Arthur Ernest;male;64.0;0;0;693;26.0;;S
期望的输出:
356;No;3;Vanden Steen, Mr. Leo Peter;male;28.0;0;0;345783;9.50;;S
546;No;1;Nicholson,Mr.Arthur Ernest;male;64.0;0;0;693;26.00;;S
答案1
脚本的最后一行与命令行上运行的脚本不同。没有理由添加这两个反斜杠。
s/(\[0-9]+\.[0-9]{2}\)[0-9]+/\1/
应该
s/([0-9]+\.[0-9]{2})[0-9]+/\1/
(另外,您不需要在第一个命令中转义分号s///
,但这不是问题,因为它只是被忽略)
答案2
像这样的语言更容易使用允许格式化浮点数的语言:
$ awk -F ';' 'BEGIN { OFS=FS } { $(NF-2) = sprintf("%.2f", $(NF-2)) }; 1' file
356;No;3;Vanden Steen, Mr. Leo Peter;male;28.0;0;0;345783;9.50;;S
546;No;1;Nicholson, Mr. Arthur Ernest;male;64.0;0;0;693;26.00;;S
该awk
程序将从末尾开始重写第三个;
分隔字段作为具有两位小数的浮点数。这将执行舍入,因此0.009
变为0.01
。在调用中使用int($(NF-2)*100)/100)
in place of just来进行截断。$(NF-2)
sprintf()
你的sed
表达式有太多反斜杠。特别是,您在扩展正则表达式中使用了\)
必须结束捕获组的位置,并且使用了 which来禁用重要的括号表达式,并使用了不必要的in 来代替。)
\[
[
\;
;
用标准sed
表达:
s/\(\.[0-9]\)\(\(;[^;]*\)\{2\}\)$/\10\2/
s/\(\.[0-9][0-9]\)[0-9]\{1,\}\(\(;[^;]*\)\{2\}\)$/\1\2/
与扩展正则表达式相同(目前与 一起使用是非标准的sed -E
):
s/(\.[0-9])((;[^;]*){2})$/\10\2/
s/(\.[0-9][0-9])[0-9]+((;[^;]*){2})$/\1\2/
这些应该比您的表达式更安全,因为它们明确匹配我们修改的字段之后的最后两个字段。因此,我们意外修改随机浮点值的风险较小。