当输入中存在正斜杠 (/) 时,gawk 中的算术(除法) - 也许有多个字段分隔符?

当输入中存在正斜杠 (/) 时,gawk 中的算术(除法) - 也许有多个字段分隔符?

我有一个文件,其行类似于以下内容(不幸的是,这是仅有的其他软件输出结果的格式):

1 2 3 5/2 7 17/5 9 10/3 15

我需要将其替换为以下行:

1 2 3 2.5 7 3.4 9 3.33 15

换句话说,我希望 GAWK 进行除法并将分数(有理数)替换 5/2, 17/5 and 10/3 为十进制值 2.5, 3.4 and 3.33.

我尝试了多个 FS(字段分隔符),但没有任何效果。使用 GAWK 执行此操作的好方法是什么?谢谢。

slash (/)如果我将 改为a会更容易吗colon (:)

我为什么要问这个问题?我试图搜索是否/是 .. 的子字符串$i(如果答案是肯定的,那么我会将split()$i 分成两部分,然后进行除法)。

我在其他地方读到,为了检查字段是否$i以 开头F,他们使用if ($i~/^F/)-- 所以我尝试了if ($i~///),然后if ($i~/"/"/),然后if ($i~/\//) (escaping / with a \)等等。这些都不起作用。所以我认为/是 Awk 中的一个特殊字符。为了避免特殊字符的复杂化,我想,让我用一下吧:

答案1

迭代字段并拆分每个字段/。如果拆分恰好生成两个子字符串,请使用它们来计算字段的新值:

$ awk '{ for (i=1; i<=NF; ++i) if (split($i,a,"/")==2) $i = a[1]/a[2] };1' file
1 2 3 2.5 7 3.4 9 3.33333 15

对于两位小数,请使用%.2f格式说明符sprintf()

$ awk '{ for (i=1; i<=NF; ++i) { if (split($i,a,"/")==2) $i = sprintf("%.2f",a[1]/a[2]) } };1' file
1 2 3 2.50 7 3.40 9 3.33 15

同样,使用磨坊主

$ mlr --nidx put 'for (k,v in $*) { a=splitnv(v,"/"); if (length(a)==2) { $[k]=a[1]/a[2] } }' file
1  2  3  2.500000  7  3.400000  9  3.333333  15
$ mlr --nidx put 'for (k,v in $*) { a=splitnv(v,"/"); if (length(a)==2) { $[k]=fmtnum(a[1]/a[2],"%.2f") } }' file
1  2  3  2.50  7  3.40  9  3.33  15

请注意,使用nidx输入和输出格式时,默认的字段分隔符是单个空格字符。这意味着问题中显示的输入有 17 个字段,其中一些字段为空。这些都在输出中复制,这意味着空格被保留。

答案2

使用它更容易(预装的系统也比的 GNU 实现perl多得多):perlgawkawk

perl -pe 's{(\d+)/(\d+)}{sprintf "%.2f", $1/$2}ge'

或者:

perl -pe 's{\d+/\d+}{sprintf "%.2f", eval$&}ge'

s用 后两位数字格式化的除法结果替换数字/数字.

perl -pe 's{(?<!\S)\d+/\d+(?!\S)}{sprintf "%.2f", eval$&}ge'

将数字/数字前面和/或后面的非白色S节奏(例如1/0x2A1/2...)单独保留。

相关内容