如何使用命令行计算文本文件中单词出现的次数?


43

我有一个很大的JSON文件,它位于一行上,因此我想使用命令行来计算该文件中单词出现的次数。我怎样才能做到这一点?


目前尚不清楚该单词是否{ "key": "the key" }应在JSON数据的键和值中都匹配,即是否应该对字符串进行key一次或两次计数。
Kusalananda

Answers:


45
$ tr ' ' '\n' < FILE | grep WORD | wc -l

其中tr用换行符替换空格,grep过滤所有与WORD匹配的结果行​​,wc并对剩余的行进行计数。

甚至可以wc使用-cgrep选项保存零件:

$ tr ' ' '\n' < FILE | grep -c WORD

-c选项由POSIX定义。

如果不能保证单词之间有空格,则必须使用其他字符(作为定界符)进行替换。例如替代tr零件是

tr '"' '\n'

要么

tr "'" '\n'

如果要替换双引号或单引号。当然,您也可以使用tr一次替换多个字符(考虑不同种类的空格和标点符号)。

如果您需要计算WORD但不计算前缀WORD,WORD后缀或前缀WORD后缀,则可以将WORD模式包含在行首/行尾标记中:

grep -c '^WORD$'

在我们的上下文中,这等效于单词开头/结尾标记:

grep -c '\<WORD\>'

如果没有空格,即字段名用引号引起来怎么办?例如“田野”
神话

@mythz:然后用tr将换行符替换为引号。我将更新答案。
maxschlepzig

1
这个答案在很多方面都是错误的。含糊不清:您应该解释如何提出一个能tr完成此任务的命令,而不是提出在所有情况下都不会起作用的示例。它还将匹配包含您要查找的单词的单词。该grep -o '\<WORD\>' | wc -l解决方案优越得多。
sam hocevar 2011年

1
@Sam,这个问题有点悬而未决,如果要搜索像“ WORD”或“ \ <WORD \>”之类的单词-您可以用两种方式阅读它。即使您以第二种方式并且仅以第二种方式阅读它,那么我的答案也只会以一种方式不正确。;)并且'grep -o'解决方案只有支持POSIX未指定的-o选项,才是更好的选择。。。模糊...
maxschlepzig

1
@Kusalananda,嗯,这仍然是一个事件。但是,如果您不想计算这样的子字符串匹配数,请在此处阅读我的答案的最后一段和我以前的评论。
maxschlepzig

24

使用GNU grep,可以使用: grep -o '\<WORD\>' | wc -l

-o 在单独的一行上打印每行的每个匹配部分。

\<断言一个单词的开头和\>断言一个单词的结尾(类似于Perl的\b),因此可以确保您不匹配单词中间的字符串。

例如,

$ python -c'导入此'| grep'\ <一个\>'
应该有一种 -最好只有一种-显而易见的方法。
命名空间是一个很棒的主意-让我们做更多这些吧!
$ python -c'导入此'| grep的-o '\ <一个\>'
 一个
一个
一个
$蟒蛇-c '导入此' | grep -o'\ <一个\>'| wc -l
3

1
或者只是grep -wo WORD | wc -l
斯特凡Chazelas

10

不幸的是,不适用于GNU coreutils

grep -o -c WORD file

如果它可以在您的平台上运行,那将是一个优雅而直观的解决方案。但是GNU人士仍在思考。


2
糟糕的是,该错误仍在打开:savannah.gnu.org/bugs/?
33080

1
太糟糕了,这将是最优雅的选择
MasterScrat

这对我有用!
ThisaruG

错了 这将计算带有WORD模式的行数。OP希望出现的总数。
皮埃尔·B

@PierreB这就是为什么我说GNU grep在这里有一个错误。这不是从POSIX清除合并的语义什么-c-o应如此,这是目前不便于携带。感谢您的评论;我已经更新了这个答案。
三人房

7
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

该命令进行以下操作:

  1. 用空格替换所有非字母数字字符。
  2. 所有换行符也将转换为空格。
  3. 将所有多个空格减少为一个空格
  4. 现在,所有空格都将转换为换行符。一行中的每个单词。
  5. 将所有单词翻译成小写,以避免“ Hello”和“ Hello”成为不同的单词
  6. 按文本排序
  7. 计算并删除相等的行
  8. 倒序排序以计算最常用的单词
  9. 为每个单词添加一个行号,以便整体了解单词位置

例如,如果我想分析第一条Linus Torvald消息:

寄件人:torvalds@klaava.Helsinki.FI(Linus Benedict Torvalds)新闻组:comp.os.minix主题:minix您最想看到什么?摘要:我的新操作系统的小型民意调查Message-ID:<1991Aug25.205708.9541@klaava.Helsinki.FI>日期:91 Aug 8 20:57:08 GMT组织:赫尔辛基大学

大家好,您都在使用minix –

我正在为386(486)AT克隆做一个(免费)操作系统(只是一个业余爱好,不会像gnu这样大而专业)。自四月以来一直在酝酿之中,并且已经开始准备。我希望得到人们对minix中喜欢/不喜欢的东西的任何反馈,因为我的操作系统在某种程度上类似于它(文件系统的物理布局(由于实际原因))。

我目前已经移植了bash(1.08)和gcc(1.40),而且一切似乎正常。这意味着我将在几个月内得到一些实用的信息,并且我想知道大多数人想要的功能。欢迎任何建议,但我不能保证会实施它们。

莱纳斯(torvalds@kruuna.helsinki.fi)

PS。是的-它没有任何minix代码,并且具有多线程fs。它不是很稳定(使用386任务切换等),它可能永远不会支持AT硬盘以外的任何其他功能,因为这就是我拥有的全部:-(。

我创建一个名为linus.txt的文件,粘贴内容,然后在控制台中编写:

sed -e 's/[^[:alpha:]]/ /g' linus.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

输出将是:

 1        7 i
 2        5 to
 3        5 like
 4        5 it
 5        5 and
 6        4 minix
 7        4 a
 8        3 torvalds
 9        3 of
10        3 helsinki
11        3 fi
12        3 any
13        2 would
14        2 won
15        2 what
16        ...

如果只想显示前20个字:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | head -n 20

是要注意重要的命令TR“AZ”“A-Z”确实不能支持UTF-8 还没有,所以在外语单词滑雪后会被翻译成阅。

如果只想搜索一个单词的出现,则可以在末尾添加grep:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\sword_to_search_for$"

在名为search_freq的脚本中:

#!/bin/bash
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\s$1$"

该脚本必须调用:

 search_freq word_to_search_for

sed: -e expression #2, char 7: unterminated s'command`,这也算所有单词,对不对?但是OP仅询问了一个特定的对象。还有一点解释会很好。
phk

对不起,我有一个错误。我重新制作了命令,并评论了答案。我认为,从这个问题来看,不可能知道他是否希望只出现一个单词或出现频率。但是,如果您只想得到一个单词,可以在末尾添加一个grep。
罗杰·博雷尔2013年

3

根据您是想匹配键中还是JSON数据值中的单词,您可能只想从数据中提取键或值。否则,如果某些单词同时作为键和值出现,那么您可能会数很多次单词。

要提取所有密钥:

jq -r '..|objects|keys[]' <file.json

这将递归地测试当前事物是否是对象,如果存在,它将提取键。输出将是键列表,每行一个。

要提取所有值:

jq -r '..|scalars' <file.json

这以相似的方式工作,但是步骤较少。

然后,您可以通过管道传递上述内容的输出grep -c 'PATTERN'(以使某些模式与键或值grep -c -w -F 'WORD'匹配),或(与键或值中的单词匹配),或grep -c -x -F 'WORD'(以匹配完整的键或值),或类似方式,通过做你的计数。


0

我有这样的json:"number":"OK","number":OK"在一行中重复多次。

我简单的“确定”计数器:

sed "s|,|\n|g" response | grep -c OK


-1

我已经使用下面的awk命令来查找出现的次数

示例文件

猫文件1

praveen ajay 
praveen
ajay monkey praveen
praveen boy praveen

命令:

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

输出

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

5

或者只是awk '{sum+=gsub("praveen","")} END {print sum+0}'
G-Man

让我知道为什么对我的答案投反对票
Praveen Kumar BS
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.