是否可以使用 sed 格式化浮点数以扩展到相同的精度,例如小数点后8位? 因为这个问题是更大背景的一部分,所以 使用 GNU sed
是非常重要的输入示例:
0
126
99.0234
.38
-47.88
-234.23001101
40565004.22
目标是将尾随 0 附加到每个数字,直到达到所需的精度。 可以肯定的是,输入的数字中小数点后的位数都不会超过所需的精度。另一个(次要)目标是在小数点前添加前导零(如果缺少)。
与 bash
LC_NUMERIC=en_US.UTF-8 printf "%0.8f" .123
一样有效。
实现的输出是:
0.00000000
126.00000000
99.02340000
0.38000000
-47.88000000
-234.23001101
40565004.22000000
到目前为止我发现的只是限制位数,而不是扩展。
另一种解决方案是调用 shell 命令
LC_NUMERIC=en_US.UTF-8 printf "%0.8f\n" \3
用于 sed 处理中的特定匹配组(此处:第三个匹配组)。
输入:
<rowNo>|<date time>|<number>
(示例:1|2024-02-01 00:27:16|.38
,数字如上)
命令(显然不起作用,用于第三场比赛组处理):
sed 's/^\([0-9]*\)|\(.*\)|\([0-9\.]*\)/\1|\2|$(LC_NUMERIC=en_US.UTF-8 printf "%.8f\n" \3))/g' test.csv
这个 sed 命令可能就是您正在寻找的:
sed 's/^[.]/0&/
/[.]/!s/$/./
s/$/00000000/
s/\([.].\{8\}\).*/\1/
' input
可能不是最微妙的,但它是纯粹的
sed
sed 's/^\([^.]*\)$/\1.00000000/;s/\(\.[0-9]*\)$/\100000000/;s/\(\.........\).*/\1/'
3 个命令。第一个添加
.00000000
如果没有 .
00000000
以确保我们可能有太多的小数位,但永远不会太少(如果不检查 .
,它可能会更简单,但这有点防御性:它不会添加 0
,如果,由于某种原因,即使在第一个命令之后也没有.
).
之后仅保留 8 个字符(如果有的话)
关于:
因为这个问题是更大背景的一部分,所以有必要 使用 GNU sed
仅针对这个问题,您不应该尝试使用 sed,如果它是更大上下文的一部分,那么您绝对不应该使用 sed。 sed 对于单个行上的简单 s/old/new/ 非常有用,但对于其他任何内容,请使用 awk 代替(或 perl/ruby/python/等,如果您不介意 POSIX 不强制存在的工具)。
关于:
另一种解决方案是调用 shell 命令
对于特定比赛 sed 处理中的组(此处:第三个匹配组)。LC_NUMERIC=en_US.UTF-8 printf "%0.8f\n" \3
这会导致 sed 为每个数字生成一个子 shell,这会非常慢,并且可能会出现其他问题。
鉴于您到目前为止所告诉我们的内容,要求 sed 解决方案类似于要求我们帮助您搬起石头砸自己的脚,所以不要这样做 - 以下是您如何能够简洁、稳健、高效、易于维护地完成您想要的事情并可移植地使用任何 awk:
$ awk '{printf "%0.8f\n", $0}' file
0.00000000
126.00000000
99.02340000
0.38000000
-47.88000000
-234.23001101
40565004.22000000
我在你问题的其他地方看到你说输入实际上是 3 个
|
分隔的字段(另一个线索是你应该使用 awk 而不是 sed,因为 awk 有特定的语言结构来支持字段,而 sed 没有)和你想要的数字修改存储在第三个字段中的内容,如下所示:
$ cat file
1|2024-02-01 00:27:16|0
1|2024-02-01 00:27:16|126
1|2024-02-01 00:27:16|99.0234
1|2024-02-01 00:27:16|.38
1|2024-02-01 00:27:16|-47.88
1|2024-02-01 00:27:16|-234.23001101
1|2024-02-01 00:27:16|40565004.22
在这种情况下:
$ awk -F'[|]' -v OFS='|' '{$3=sprintf("%0.8f", $3)} 1' file
1|2024-02-01 00:27:16|0.00000000
1|2024-02-01 00:27:16|126.00000000
1|2024-02-01 00:27:16|99.02340000
1|2024-02-01 00:27:16|0.38000000
1|2024-02-01 00:27:16|-47.88000000
1|2024-02-01 00:27:16|-234.23001101
1|2024-02-01 00:27:16|40565004.22000000
顺便说一下,你说过
printf "%0.8f"
可以工作,下面是它对小数点后超过 8 位数字的作用:
$ printf "%0.8f\n" .111111117
0.11111112
请注意,最终输入数字
...17
在输出中四舍五入为 ...2
。
如果我们在上面的 awk 脚本中使用类似的输入,我们会得到相同的输出:
$ awk '{printf "%0.8f\n", $0}' <<< .111111117
0.11111112
您不会从迄今为止发布的任何 sed 脚本中获得相同的输出,它们只是截断为
0.11111111
。
您可以在 https://www.gnu.org/software/gawk/manual/gawk.html#Round-Function 中查看有关舍入数字的更多信息。