2017-10-21 126 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