如何使用扩展正则表达式创建 sed 脚本

如何使用扩展正则表达式创建 sed 脚本

我有两个 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/

这些应该比您的表达式更安全,因为它们明确匹配我们修改的字段之后的最后两个字段。因此,我们意外修改随机浮点值的风险较小。

相关内容