2017-10-21 72 views
0

已关注此线程BASH Finding palindromes in a .txt file我无法弄清楚我的脚本在做什么错。在文本文件中计数回文

#!/bin/bash 
search() { 
tr -d '[[:punct:][:digit:]@]' \ 
| sed -E -e '/^(.)\1+$/d'  \ 
| tr -s '[[:space:]]'   \ 
| tr '[[:space:]]' '\n' 
} 

search "$1" 

paste <(search <"$1") <(search < "$1" | rev)  \ 
| awk '$1 == $2 && (length($1) >=3) { print $1 }' \ 
| sort | uniq -c 

所有从这个脚本得到的都是整个文本文件的输出。我只想输出回文> = 3和尽数如

425做

120非

等我的文本文件被称为sample.txt的,每次我运行该脚本:猫​​样。 txt |源回文我得到消息'bash::没有这样的文件或目录'。

+0

你想算回文数,还是要数*每个回文*文本文件中出现的次数? – Socowi

+0

这个问题涉及一个courswork任务(由我设定),并发布部分解决方案,并要求在堆栈交换解决方案是违反剽窃和合谋条例。如果您在使代码正常工作时遇到问题,请向我或助教寻求帮助。请把这个问题删除? –

回答

3

使用AWKsed的

awk 'function palindrome(str) {len=length(str); for(k=1; k<=len/2+len%2; k++) { if(substr(str,k,1)!=substr(str,len+1-k,1)) return 0 } return 1 } {for(i=1; i<=NF; i++) {if(length($i)>=3){ gsub(/[^a-zA-Z]/,"",$i); if(length($i)>=3) {$i=tolower($i); if(palindrome($i)) arr[$i]++ }} } } END{for(i in arr) print arr[i],i}' file | sed -E '/^[0-9]+ (.)\1+$/d' 

测试在1.2GB文件和执行时间为〜400 40岁(i5-6440HQ @ 2.60GHz/4 cores/16GB)

说明:

awk ' 
    function palindrome(str)    # Function to check Palindrome 
    { 
     len=length(str); 
     for(k=1; k<=len/2+len%2; k++) 
     { 
      if(substr(str,k,1)!=substr(str,len+1-k,1)) 
      return 0 
     } 
     return 1 
    } 

    { 
     for(i=1; i<=NF; i++)    # For Each field in a record 
     { 
      if(length($i)>=3)    # if length>=3 
      { 
       gsub(/[^a-zA-Z]/,"",$i); # remove non-alpha character from it 
       if(length($i)>=3)   # Check length again after removal 
       { 
        $i=tolower($i);  # Covert to lowercase 
        if(palindrome($i))  # Check if it's palindrome 
         arr[$i]++   # and store it in array 
       } 
      } 
     } 
    } 

    END{for(i in arr) print arr[i],i}' file | sed -E '/^[0-9]+ (.)\1+$/d' 

sed -E '/^[0-9]+ (.)\1+$/d':从最终结果中检查哪些字符串是由重复的字符组成,如AAA,BBB等,并将其删除。


老答(编辑之前)

,如果你想你可以试试下面的步骤:

步骤1:预处理
删除所有不必要的字符,并将结果在临时文件中

tr -dc 'a-zA-Z\n\t ' <file | tr ' ' '\n' > temp 

tr -dc 'a-zA-Z\n\t '这将所有删除除字母,\n\t,空间

tr ' ' '\n'这将空间转换到\n每个单词在换行分离

步骤2:处理

grep -wof temp <(rev temp) | sed -E -e '/^(.)\1+$/d' | awk 'length>=3 {a[$1]++} END{ for(i in a) print a[i],i; }' 

grep -wof temp <(rev temp)这会给你所有的回文
-w:只选择那些包含匹配表单的行整个词。 例如:level将不匹配与levelAAA
-o:只打印匹配的组
-f:要使用的每个字符串中temp文件作为图案<(rev temp)

sed -E -e '/^(.)\1+$/d'搜索:这将删除的同形成字信件像AAABBBBB

awk 'length>=3 {a[$1]++} END{ for(i in a) print a[i],i; }':这将过滤使length>=3单词和计数的频率,最后打印出结果

实施例:

输入文件:

$ cat file 
kayak nalayak bob dad , pikachu. meow !! bhow !! 121 545 ding dong AAA BBB done 
kayak nalayak bob dad , pikachu. meow !! bhow !! 121 545 ding dong AAA BBB done 
kayak nalayak bob dad , pikachu. meow !! bhow !! 121 545 ding dong AAA BBB done 

输出:

$ tr -dc 'a-zA-Z\n\t ' <file | tr ' ' '\n' > temp 
$ grep -wof temp <(rev temp) | sed -E -e '/^(.)\1+$/d' | awk 'length>=3 {a[$1]++} END{ for(i in a) print a[i],i; }' 
3 dad 
3 kayak 
3 bob 
2

运行脚本

脚本希望该文件作为参数给出。该脚本不读取stdin。

删除脚本中间的行search "$1"。它不是链接答案的一部分。

使脚本可执行使用chmod u+x path/to/palindrome

使用path/to/palindrome path/to/sample.txt调用脚本。如果所有的文件都在当前工作目录,则命令为

./palindrome sample.txt 

替代文字

有时链接的脚本工作,有时没有。我还没有找到原因。不过,我写了一个替代脚本,做同样的,也是有点清洁:

#! /bin/bash 
grep -Po '\w{3,}' "$1" | grep -Evw '(.)\1*' | sort > tmp-words 
grep -Fwf <(rev tmp-words) tmp-words | uniq -c 
rm tmp-words 

保存脚本,使它可执行文件,并以文件作为第一个参数调用它。

3

只是快速的Perl替代:

perl -0nE 'for(/(\w{3,})/g){ $a{$_}++ if $_ eq reverse($_)} 
      END {say "$_ $a{$_}" for keys %a}' 
  • in Perl,$_应被解读为“it”。
  • for(/(\w{3,})/g) ......为所有相关的单词(可能需要一些工作,拒绝误报像 “12a21”)
  • if $_ eq reverse($_) ......如果是回文
  • END {say "$_ $a{$_}" for...} ...告诉我们所有的 S和的号码

\感谢{sokowi,蝙蝠侠}

+1

它不会产生所需的结果,因为它会考虑像OP不想要的“AAA”这样的数字和单词。顺便说一句很好的解 – batMan

+0

@batMan,谢谢。 >“AAA”我没有看到任何关于避免AAA的限制。 > ...“数字” - 你是完全正确的! – JJoao

+0

@Socowi,谢谢。如果我没有记错,'reverse'用于数组,而不是字符串。 'reverse(“abc”)=“abc”' – JJoao