任务
这里的参数是文件名!该文件包含文本。脚本的任务是确定哪个单词最常包含(换句话说)。
输入和输出示例
(例如,文本是:打球、足球、篮球、雪球 - 因此球是赢家,因为它是其他三个世界的一部分)。
到目前为止我的代码
到目前为止我已经完成了这段代码,但它并不适用于每个输出
!/bin/sh
awk '{for(i=2;i<NF;i++) {s=$i; for(j=i+1;j<=NF;j++) print s=s FS $j}}' $1 | sort | uniq -c | sort -k1,1rn -k2 | sed 's/ *[^ ]* *//;q' | cut -f1 -d" "
答案1
如果单词列表位于名为 的文件中words
,每行只有一个单词(可能是使用 来tr ' ' '\n' <originalwords >words
将原始列表拆分为多行而创建的),则循环
while IFS= read -r word; do
grep -F -o -e "$word" words
done <words | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'
将输出出现次数最多的单词作为列表中单词的一部分(或者,如果许多单词出现相同次数,则输出列表中第一个出现的单词)。
它通过使用列表本身作为一组模式来与列表进行匹配来实现此目的。我们-o
要求在单独的行上返回匹配的子字符串。
单独循环的输出以及问题中给出的列表将是
play
ball
ball
ball
ball
football
basketball
snowball
然后只需计算这些单词并选出最常出现的单词即可。
作为一个完整的脚本,具有临时文件处理:
#!/bin/sh
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT # delete temporary file upon exiting
tr -s ' ' '\n' <"${1:-/dev/stdin}" >"$tmpfile" # convert into word list
while IFS= read -r word; do
grep -F -o -e "$word" "$tmpfile"
done <"$tmpfile" | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'
如果没有指定文件,该脚本还会从标准输入中读取。
答案2
awk '{
for (i=1; i<=NF; i++) {
uwords[$i] = 0
allwords[++idx] = $i
}
}
END {
if (idx == 0) exit
max = 0
for (w in uwords) {
count = 0
for (i=1; i<=idx; i++) {
if (allwords[i] ~ w) count++;
}
if (count > max) {
max = count
maxw = w
}
}
print maxw
}'
扫描输入并提取唯一单词列表和所有单词列表。 (我想我们不需要唯一单词的列表,但在输入较大的情况下它可能会使事情变得更有效。)然后,对于每个唯一单词,计算文件中有多少单词与其匹配。 (因此,如果文件包含football football football
,则 向 计数 3。ball
)跟踪匹配最多的那个。
uwords
如果出现平局,它会报告(唯一单词)数组中第一个出现的单词。这不一定是文件中出现的第一个,也不是按字母顺序排列的第一个。
如果任何单词包含,这可能会产生意想不到的结果.
,*
或者[
。
如果您更喜欢 Kusalananda 的 shell+awk 方法,但不希望出现边缘情况错误,请执行以下操作:
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT # delete temporary file upon exiting
tr -s ' ' '\n' < "${1:-/dev/stdin}" > "$tmpfile" # convert into word list
sort -u "$tmpfile" | while IFS= read -r word
do
grep -F -o -e "$word" "$tmpfile"
done | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'
通过对单词列表进行排序,我们得到了唯一单词的列表,因此不会对任何单词进行多次计数。
请注意,此代码明确假设最多有一个输入文件(但可能没有文件;即从 stdin 读取)。这与问题的措辞是一致的。但是,如果可能有任意数量的输入文件(零、一、或者更多),将该tr
行更改为
cat -- "$@" | tr -s ' ' '\n' > "$tmpfile" # convert into word list
可以说这是一个 UUOC,但是
- 它处理两个或多个输入文件的情况,并且
- 它比 . 更具可读性
< "${1:-/dev/stdin}"
。