【问题标题】:How can I count most occuring sequence of 3 letters within a word with a bash script如何使用 bash 脚本计算一个单词中出现最多的 3 个字母序列
【发布时间】:2020-01-13 16:48:43
【问题描述】:

我有一个类似的示例文件

XYZAcc
ABCAccounting
Accounting firm
Accounting Aco
Accounting Acompany
Acoustical consultant

这里我需要 grep 一个单词中出现最多的 3 个字母序列

输出应该是

acc = 5 aco = 3

这在 Bash 中可行吗?

我完全不知道如何使用 awk、sed、grep 来完成它。

任何线索如何可能......

PS:没有输出,因为我不知道该怎么做,我不想写不必要的 awk -F, xyz abc... 这对任何地方都没有帮助...

【问题讨论】:

  • 由于部分匹配,解决方案会很复杂——这不是单词匹配
  • 您发布的那个输入文件在我看来不像 CSV。您是否只发布了真实 CSV 的一列?请发布真正具有代表性的示例输入和预期输出,涵盖您的所有用例(跨行匹配、字段内匹配、部分匹配与完整匹配、正则表达式与字符串匹配等)。
  • 在您的示例中,cou 也会出现 5 次。 Bash/grep/sed 并不是这种操作的最佳语言。第一个问题,存在哪些独特的三字母代码?很难回答。
  • @EdMorton 它是我保存为 CSV 的文件 .. 只有 1 列 ;))
  • 那么它只是一个纯文本文件,尽管您在其末尾添加了任何扩展名。您可以将其命名为 foo.html 或 foo.docx 或其他任何名称,但这不会使其成为那种类型的文件 - 内容使其成为任何文件类型,在这种情况下,它只是一个纯文本文件,因为没有分隔符在其中将使其成为 CSV。说它是 CSV 文件只是令人困惑。

标签: linux bash awk sed


【解决方案1】:

以下是我认为您正在尝试做的事情的开始方法:

$ cat tst.awk
BEGIN { stringLgth = 3 }
{
    for (fldNr=1; fldNr<=NF; fldNr++) {
        field = $fldNr
        fieldLgth = length(field)
        if ( fieldLgth >= stringLgth ) {
            maxBegPos = fieldLgth - (stringLgth - 1)
            for (begPos=1; begPos<=maxBegPos; begPos++) {
                string = tolower(substr(field,begPos,stringLgth))
                cnt[string]++
            }
        }
    }
}
END {
    for (string in cnt) {
        print string, cnt[string]
    }
}

.

$ awk -f tst.awk file | sort -k2,2nr
acc 5
cou 5
cco 4
ing 4
nti 4
oun 4
tin 4
unt 4
aco 3
abc 1
ant 1
any 1
bca 1
cac 1
cal 1
com 1
con 1
fir 1
ica 1
irm 1
lta 1
mpa 1
nsu 1
omp 1
ons 1
ous 1
pan 1
sti 1
sul 1
tan 1
tic 1
ult 1
ust 1
xyz 1
yza 1
zac 1

【讨论】:

  • 哈,我越来越近了,我做了1-NF,但后来tolower 循环了j=1;j&lt;=length(s)-3 和arr[substr(s,j,3)]++。在END 中颠倒输出顺序并通过管道传送到sort -r -n
【解决方案2】:

这是solution of Ed Morton 的替代方法。它的循环较少,但需要更多的内存。这个想法是不关心空格或任何非字母字符。我们最终将它们过滤掉。

awk -v n=3 '{ for(i=length-n+1;i>0;--i) a[tolower(substr($0,i,n))]++ }
            END {for(s in a) if (s !~ /[^a-z]/) print s,a[s] }' file

当您使用 GNU awk 时,您可以通过将每条记录设置为一个单词来进行一些不同的操作并进行优化。这样就不需要发生结束选择:

awk -v n=3 -v RS='[[:space:]]' '
    (length>=n){ for(i=length-n+1;i>0;--i) a[tolower(substr($0,i,n))]++ }
    END {for(s in a) print s,a[s] }' file

【讨论】:

    【解决方案3】:

    这可能对你有用(GNU sed、sort 和 uniq):

    sed -E 's/.(..)/\L&\n\1/;/^\S{3}/P;D' file |
    sort |
    uniq -c |
    sort -s -k1,1rn |
    sed -En 's/^\s*(\S+)\s*(\S+)/\2 = \1/;H;$!b;x;s/\n/ /g;s/.//p'
    

    使用第一个 sed 调用输出 3 个字母的小写单词。

    对单词进行排序。

    计算重复次数。

    以相反的数字顺序对计数进行排序,保持字母顺序。

    使用第二个 sed 调用将结果操作为所需的格式。


    如果您只想要重复的行并按字母顺序和大小写,请使用:

    sed -E 's/.(..)/&\n\1/;/^\S{3}/P;D' file |
    sort |
    uniq -cd |
    sed -En 's/^\s*(\S+)\s*(\S+)/\2 = \1/;H;$!b;x;s/\n/ /g;s/.//p
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-10
      • 2020-07-05
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 2015-11-18
      • 2021-12-27
      • 1970-01-01
      相关资源
      最近更新 更多