【发布时间】:2021-12-26 20:31:59
【问题描述】:
假设我有文件:
$ cat file
This, that;
this-that or this.
(行尾的标点符号并不总是存在...)
现在我想计算 单词(单词被定义为一个或多个不区分大小写的 ascii 字母。)在典型的 POSIX *nix 中,您可以这样做:
sed -nE 's/[^[:alpha:]]+/ /g; s/ $//p' file | tr ' ' "\n" | tr '[:upper:]' '[:lower:]' | sort | uniq -c
1 or
2 that
3 this
使用 grep,您可以将其缩短一点,以仅匹配您定义为单词的内容:
grep -oE '[[:alpha:]]+' file | tr '[:upper:]' '[:lower:]' | sort | uniq -c
# same output
使用 GNU awk,您可以使用 FPAT 仅复制您想要的匹配项(忽略排序...):
gawk -v FPAT="[[:alpha:]]+" '
{for (i=1;i<=NF;i++) {seen[tolower($i)]++}}
END {for (e in seen) printf "%4s %s\n", seen[e], e}' file
3 this
1 or
2 that
现在尝试在 POSIX 中复制 awk 我试过了:
awk 'BEGIN{FS="[^[:alpha:]]+"}
{ for (i=1;i<=NF;i++) seen[tolower($i)]++ }
END {for (e in seen) printf "%4s %s\n", seen[e], e}' file
2
3 this
1 or
2 that
注意2 顶部有空白。这是因为第 1 行末尾的 ; 和第 2 行末尾的 . 有空白字段。如果删除行尾的标点符号,这个问题就会消失。
您可以通过在 awk 中设置 RS="" 来部分修复它(除了最后一行),但仍然会在最后(唯一)行中获得一个空白字段。
我也可以这样解决:
awk 'BEGIN{FS="[^[:alpha:]]+"}
{ for (i=1;i<=NF;i++) if ($i) seen[tolower($i)]++ }
END {for (e in seen) printf "%4s %s\n", seen[e], e}' file
这似乎不太直接。
我是否缺少使 POSIX awk 的行为类似于 GNU awk 的 FPAT 解决方案的惯用修复方法?
【问题讨论】:
-
该模式不需要
-P,它没有特定于pcre的内容:-E可以。 -
注意:并非所有行的末尾都有非字母,因此空白字段不会总是存在...