有没有一种简单的方法可以从终端计算文件中单词的字符数?

有没有一种简单的方法可以从终端计算文件中单词的字符数?

我的文件中有 1 亿行。

每行只有一列。

例如

aaaaa
bb
cc
ddddddd
ee

我想列出字符数

像这样

2 character words - 3
5 character words - 1
7 character words - 1

ETC。

有没有简单的方法可以在终端中执行此操作?

答案1

$ awk '{ print length }' file | sort -n | uniq -c | awk '{ printf("%d character words: %d\n", $2, $1) }'
2 character words: 3
5 character words: 1
7 character words: 1

第一个awk过滤器将仅打印名为 的文件中每行的长度file。我假设该文件每行包含一个单词。

(按升序sort -n对输出中的行进行数字排序)和(计算每行连续出现的次数)将为给定数据创建以下输出:awkuniq -c

   3 2
   1 5
   1 7

然后由第二个awk脚本对其进行解析,该脚本将每一行解释为“具有 Y 个字符的 X 行”并生成所需的输出。


awk另一种解决方案是在数组中完成所有操作并保存长度计数。这是效率、可读性/易于理解性(以及可维护性)之间的权衡,哪个解决方案是“最好的”。

替代解决方案:

$ awk '{ len[length]++ } END { for (i in len) printf("%d character words: %d\n", i, len[i]) }' file
2 character words: 3
5 character words: 1
7 character words: 1

答案2

awk另一种单独完成这一切的方法

$ awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' ip.txt 
2 character words - 3
5 character words - 1
7 character words - 1
  • words[length()]++使用输入行的长度作为键来保存计数
  • END{for(k in words)print k " character words - " words[k]}处理完所有行后,以所需格式打印数组内容


性能比较,所选号码是两次运行中最好的号码

$ wc words.txt
 71813  71813 655873 words.txt
$ perl -0777 -ne 'print $_ x 1000' words.txt > long_file.txt
$ du -h --apparent-size long_file.txt
626M    long_file.txt

$ time awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1

real    0m20.632s
user    0m20.464s
sys     0m0.108s

$ time perl -lne '$h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}' long_file.txt > t2

real    0m19.749s
user    0m19.640s
sys     0m0.108s

$ time awk '{ print length }' long_file.txt | sort -n | uniq -c | awk '{ printf("%d character words - %d\n", $2, $1) }' > t3

real    1m23.294s
user    1m24.952s
sys     0m1.980s

$ diff -s <(sort t1) <(sort t2)
Files /dev/fd/63 and /dev/fd/62 are identical
$ diff -s <(sort t1) <(sort t3)
Files /dev/fd/63 and /dev/fd/62 are identical

如果文件只有 ASCII 字符,

$ time LC_ALL=C awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1

real    0m15.651s
user    0m15.496s
sys     0m0.120s

不知道为什么时间perl没有改变太多,可能编码必须以其他方式设置

答案3

这是一个perl等效的(带有 - 可选 - 排序):

$ perl -lne '
    $h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}
' file
2 character words - 3
5 character words - 1
7 character words - 1

答案4

替代调用 GNU awk,使用打印函数

$ awk 'BEGIN { PROCINFO["sorted_in"] = "@ind_str_asc"}
       {c[length($0)]++}
       END{
           for(i in c){printf("%s character words - %s\n",i,c[i])}
          }' infile
2 character words - 3
5 character words - 1
7 character words - 1

核心算法只是收集数组中的字符计数。结尾部分打印用 printf 格式化的收集的计数。

快速、简单,一次调用 awk。

准确地说:更多的内存用于保存数组。
但没有调用任何排序(数字数组索引设置为始终使用 PROCINFO 向上遍历排序),并且只有一个外部程序:awk,而不是多个。

相关内容