【问题标题】:Getting count of all possible substrings of length n in a file? (excluding spaces)获取文件中所有可能长度为 n 的子字符串的计数? (不包括空格)
【发布时间】:2019-08-01 22:34:07
【问题描述】:

我有一些导出文件,你可以假设它们在一行中有很多单词并且没有一行是特殊的。我看到这篇文章在文件中生成不同的单词

https://unix.stackexchange.com/questions/286464/all-possible-permutations-of-words-in-different-files-in-pairs

文件中还有一些其他的单词搜索变体。

但是对于长度为 4 的子字符串,我需要这样的东西。这里我们有子字符串和它的计数。

示例文件内容

no apples 
no apples
mango is great
banana is expensive
test

示例输出是

appl 2
pple 2
ples 2
mang 1
ango 1
grea 1
reat 1
bana 1
anan 1
nana 1
expe 1
xpen 1
pens 1
ensi 1
sive 1
nsiv 1
test 1

子字符串不一定有任何意义,它们只是文件的子字符串。文件不大,最坏的情况下不到5MB,实际上有多个文件但我在分析之前将它们合并了。

我想在 SO 中询问,因为如果这需要编写一个 shell/phyton 脚本,但是如果我们可以使用命令轻松地做到这一点,那就更感激了。

【问题讨论】:

    标签: python macos shell unix awk


    【解决方案1】:

    你也可以试试 Perl

    perl -lne ' while(/(\S+)/g) { $x=$1; 
          while($x=~/\b(?=(\w{4}))|\B(?=(\w{4}))\B|(?=(\w{4}))\b/g) { $kv{"$1$2$3"}++ }} 
           END { print "$_ $kv{$_}" for(keys %kv) }  ' file
    

    用你给定的输入

    $ cat test.txt
    no apples
    no apples
    mango is great
    banana is expensive
    test
    
    $ perl -lne ' while(/(\S+)/g) { $x=$1; 
         while($x=~/\b(?=(\w{4}))|\B(?=(\w{4}))\B|(?=(\w{4}))\b/g) { $kv{"$1$2$3"}++ }}
           END { print "$_ $kv{$_}" for(keys %kv) }  ' test.txt
    nsiv 1
    xpen 1
    reat 1
    ensi 1
    sive 1
    ples 2
    pple 2
    test 1
    appl 2
    expe 1
    anan 1
    mang 1
    ango 1
    bana 1
    pens 1
    grea 1
    nana 1
    
    $
    

    您可以在 BEGIN 块内参数化为

    $ perl -lne ' BEGIN { $t=qr(\w{5}) } 
         while(/(\S+)/g) { $x=$1; while($x=~/\b(?=($t))|\B(?=($t))\B|(?=($t))\b/g)
            { $kv{"$1$2$3"}++ }} 
               END { print "$_ $kv{$_}" for(keys %kv) }  ' test.txt
    great 1
    pples 2
    apple 2
    expen 1
    nsive 1
    banan 1
    anana 1
    ensiv 1
    pensi 1
    xpens 1
    mango 1
    
    $
    

    【讨论】:

    • 谢谢,这是另一个在我的 mac 上工作的解决方案。
    • 很高兴它起作用了!..我刚刚添加了如何参数化它..请检查
    • 有趣。这是另一种做法,使用substr 在每个单词中遍历长度为 4 的字符串:echo "banana is expensive, apple is great" | perl -wnE'while (/(\S+)/g) { $i=0; say $s while length($s = substr $1, $i++, 4) >= 4 }。提出标点符号问题(只是使用自然语言的众多问题之一);一个简单的方法,使用\w 而不是\S。但是,连字符的单词呢?那么也许使用[\w-]
    【解决方案2】:

    您可以使用此awk 解决方案来获取所有n 字母子字符串及其频率的列表:

    awk -v n=4 '{
    for (i=1; i<=NF; i++)
       for (j=1; j<=length($i)-n+1; j++)
          w[substr($i, j, n)]++
    }
    END {
       for (i in w) print i, w[i]
    }' file
    

    appl 2
    ensi 1
    nana 1
    mang 1
    sive 1
    anan 1
    nsiv 1
    grea 1
    pens 1
    xpen 1
    bana 1
    ples 2
    pple 2
    expe 1
    reat 1
    ango 1
    

    【讨论】:

    • 我将提供一个我知道子字符串计数的小内容。可能是四个长度的单词更容易。
    【解决方案3】:

    类似下面的东西可以满足你的需要:

    while read line 
    do 
      for word in $line 
      do 
      [[ ${#word} -eq 3 ]] && echo "$word" $(grep -c "$word" your_file)  
      done 
    done < your_file
    

    它将逐行逐字读取您的文件。如果单词长度为3,则输出该单词及其在文件中出现的次数

    【讨论】:

    • 将很快测试您的解决方案,但只是提供了一个示例,仅供参考
    • 抱歉,看起来您的脚本计算的单词不是所有的下标。这是我写这个问题的坏处。我提供了一个例子,现在很清楚了。
    • 但您的回答可能会更有帮助,我想人们大多需要单词而不是子字符串。
    【解决方案4】:

    所以这里的诱惑是嵌套循环......但你不想这样做,当然不是 N>3......

    python 中有 2 个不错的东西可以让这变得非常简单

    • 过滤器
    • collections.Counter

    .

    from collections import Counter
    
    s = open(somefile).read()
    # now you have a string with contents of file.
    l = s.split()
    # now you have a list of words of all lengths
    l_filtered = filter(lambda x: len(x)==n, l)
    #now you have a filtered list of only words of len n
    print (Counter(l_filtered))
    #your answer as a dict like Counter object
    

    【讨论】:

    • 将很快测试您的解决方案,但只是提供了一个示例,仅供参考
    • 您唯一需要提供的是 int nsomefile 中的文件路径
    猜你喜欢
    • 2015-11-27
    • 2021-06-14
    • 2021-02-22
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多