任务

任务

任务

这里的参数是文件名!该文件包含文本。脚本的任务是确定哪个单词最常包含(换句话说)。


输入和输出示例

(例如,文本是:打球、足球、篮球、雪球 - 因此球是赢家,因为它是其他三个世界的一部分)。


到目前为止我的代码

到目前为止我已经完成了这段代码,但它并不适用于每个输出

!/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}"

相关内容