计算文本文件中的回文数
Counting palindromes in a text file
关注了这个话题 我不知道我的脚本哪里做错了。
#!/bin/bash
search() {
tr -d '[[:punct:][:digit:]@]' \
| sed -E -e '/^(.)+$/d' \
| tr -s '[[:space:]]' \
| tr '[[:space:]]' '\n'
}
search ""
paste <(search <"") <(search < "" | rev) \
| awk ' == && (length() >=3) { print }' \
| sort | uniq -c
我从这个脚本中得到的全部是整个文本文件的输出。我只想输出回文 >=3 并计算它们,例如
425 人做了
120 非
等我的文本文件名为 sample.txt,每次我 运行 脚本都包含:cat sample.txt |源回文我收到消息 'bash: : No such file or directory'.
运行 脚本
脚本需要文件作为参数给出。该脚本不读取标准输入。
删除脚本中间的行search ""
。它不是链接答案的一部分。
使用 chmod u+x path/to/palindrome
使脚本可执行。
使用 path/to/palindrome path/to/sample.txt
调用脚本。如果所有文件都在当前工作目录下,则命令为
./palindrome sample.txt
替代脚本
链接脚本有时有效,有时无效。我还没有找出原因。然而,我写了一个替代脚本,它做同样的事情并且也更干净一些:
#! /bin/bash
grep -Po '\w{3,}' "" | grep -Evw '(.)*' | sort > tmp-words
grep -Fwf <(rev tmp-words) tmp-words | uniq -c
rm tmp-words
保存脚本,使其可执行,并使用文件作为第一个参数调用它。
使用 awk 和 sed
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]+ (.)+$/d'
在 1.2GB 文件上测试,执行时间为 ~4m 40s (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]+ (.)+$/d'
sed -E '/^[0-9]+ (.)+$/d'
:从最终结果中检查哪些字符串由 AAA
、BBB
等重复字符组成并删除它们。
旧答案(编辑前)
如果您愿意,可以尝试以下步骤:
第 1 步:预处理
删除所有不必要的字符并将结果存储在临时文件中
tr -dc 'a-zA-Z\n\t ' <file | tr ' ' '\n' > temp
tr -dc 'a-zA-Z\n\t '
这将删除所有字母,\n
,\t
, space </code></p>
<p><code>tr ' ' '\n'
这会将 space 转换为 \n
以换行分隔每个单词
第 2 步:处理
grep -wof temp <(rev temp) | sed -E -e '/^(.)+$/d' | awk 'length>=3 {a[]++} END{ for(i in a) print a[i],i; }'
grep -wof temp <(rev temp)
这会给你所有的回文
-w
: Select 仅那些包含构成整个单词的匹配项的行。
例如:level
不会与 levelAAA
匹配
-o
: 只打印匹配的组
-f
: 使用 temp
文件中的每个字符串作为模式在 <(rev temp)
中搜索
sed -E -e '/^(.)+$/d'
:这将删除由相同字母组成的单词,如 AAA
、BBBBB
awk 'length>=3 {a[]++} 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 '/^(.)+$/d' | awk 'length>=3 {a[]++} END{ for(i in a) print a[i],i; }'
3 dad
3 kayak
3 bob
只是一个快速的 Perl 替代品:
perl -0nE 'for( /(\w{3,})/g ){ $a{$_}++ if $_ eq reverse($_)}
END {say "$_ $a{$_}" for keys %a}'
- 在 Perl 中,
$_
应该读作“it”。
for( /(\w{3,})/g )
...对于所有相关词(可能需要一些工作来拒绝像“12a21”这样的误报)
if $_ eq reverse($_)
...如果它是回文
END {say "$_ $a{$_}" for...}
...告诉我们所有 its 和 its number
\谢谢{sokowi,batMan}
关注了这个话题
#!/bin/bash
search() {
tr -d '[[:punct:][:digit:]@]' \
| sed -E -e '/^(.)+$/d' \
| tr -s '[[:space:]]' \
| tr '[[:space:]]' '\n'
}
search ""
paste <(search <"") <(search < "" | rev) \
| awk ' == && (length() >=3) { print }' \
| sort | uniq -c
我从这个脚本中得到的全部是整个文本文件的输出。我只想输出回文 >=3 并计算它们,例如
425 人做了
120 非
等我的文本文件名为 sample.txt,每次我 运行 脚本都包含:cat sample.txt |源回文我收到消息 'bash: : No such file or directory'.
运行 脚本
脚本需要文件作为参数给出。该脚本不读取标准输入。
删除脚本中间的行search ""
。它不是链接答案的一部分。
使用 chmod u+x path/to/palindrome
使脚本可执行。
使用 path/to/palindrome path/to/sample.txt
调用脚本。如果所有文件都在当前工作目录下,则命令为
./palindrome sample.txt
替代脚本
链接脚本有时有效,有时无效。我还没有找出原因。然而,我写了一个替代脚本,它做同样的事情并且也更干净一些:
#! /bin/bash
grep -Po '\w{3,}' "" | grep -Evw '(.)*' | sort > tmp-words
grep -Fwf <(rev tmp-words) tmp-words | uniq -c
rm tmp-words
保存脚本,使其可执行,并使用文件作为第一个参数调用它。
使用 awk 和 sed
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]+ (.)+$/d'
在 1.2GB 文件上测试,执行时间为 ~4m 40s (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]+ (.)+$/d'
sed -E '/^[0-9]+ (.)+$/d'
:从最终结果中检查哪些字符串由 AAA
、BBB
等重复字符组成并删除它们。
旧答案(编辑前)
如果您愿意,可以尝试以下步骤:
第 1 步:预处理
删除所有不必要的字符并将结果存储在临时文件中
tr -dc 'a-zA-Z\n\t ' <file | tr ' ' '\n' > temp
tr -dc 'a-zA-Z\n\t '
这将删除所有字母,\n
,\t
, space </code></p>
<p><code>tr ' ' '\n'
这会将 space 转换为 \n
以换行分隔每个单词
第 2 步:处理
grep -wof temp <(rev temp) | sed -E -e '/^(.)+$/d' | awk 'length>=3 {a[]++} END{ for(i in a) print a[i],i; }'
grep -wof temp <(rev temp)
这会给你所有的回文
-w
: Select 仅那些包含构成整个单词的匹配项的行。
例如:level
不会与 levelAAA
匹配
-o
: 只打印匹配的组
-f
: 使用 temp
文件中的每个字符串作为模式在 <(rev temp)
sed -E -e '/^(.)+$/d'
:这将删除由相同字母组成的单词,如 AAA
、BBBBB
awk 'length>=3 {a[]++} 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 '/^(.)+$/d' | awk 'length>=3 {a[]++} END{ for(i in a) print a[i],i; }'
3 dad
3 kayak
3 bob
只是一个快速的 Perl 替代品:
perl -0nE 'for( /(\w{3,})/g ){ $a{$_}++ if $_ eq reverse($_)}
END {say "$_ $a{$_}" for keys %a}'
- 在 Perl 中,
$_
应该读作“it”。 for( /(\w{3,})/g )
...对于所有相关词(可能需要一些工作来拒绝像“12a21”这样的误报)if $_ eq reverse($_)
...如果它是回文END {say "$_ $a{$_}" for...}
...告诉我们所有 its 和 its number
\谢谢{sokowi,batMan}