BASH Palindrome Checker

时间:2014-10-28 05:06:45

标签: bash loops grep palindrome

这是我第一次在这里发帖,所以请耐心等待。

我收到了bash作业,但我的教授完全没有帮助,他的笔记也是如此。

我们的任务是过滤和打印文件中的回文。在这种情况下,目录是:

/usr/share/dict/words

单词长度范围从3到45,并且应该只过滤小写字母(给出的字典包含字符和大写字母,以及小写字母)。即“-dkas-das”,所以像“q-evvavve-q”这样的东西可能算作回文,但我不应该把它当作一个合适的结果。

无论如何,我可以让它过滤掉x个单词并返回(但不过滤掉只有小写)。

grep "^...$" /usr/share/dict/words |
grep "\(.\).\1" 

我可以使用后续行代表5个字母和7个等等:

grep "^.....$" /usr/share/dict/words |
grep "\(.\)\(.\).\2\1" 

但教授不希望如此。我们应该使用循环。我得到了这个概念,但我不知道语法,就像我说的那样,笔记非常无益。

我尝试的是设置变量x = ...和y = ..并且在while循环中,x = $ x $ y但是这不起作用(语法错误)并且x + = .. < / p>

感谢任何帮助。甚至把我的非小写字母过滤掉了。

谢谢!

编辑:

如果您要为解决方案提供解决方案或提示,则最好采用最简单的方法。 最好使用2个grep语句和一个循环。

再次感谢。

5 个答案:

答案 0 :(得分:2)

像这样:

for word in `grep -E '^[a-z]{3,45}$' /usr/share/dict/words`;
    do [ $word == `echo $word | rev` ] && echo $word;
done;

使用我的字典输出:

aha
bib
bob
boob
...
wow

<强>更新

正如评论中所指出的,将大部分字典读入for循环中的变量可能不是最有效的,并且可能会在某些shell中触发错误。这是一个更新版本:

grep -E '^[a-z]{3,45}$' /usr/share/dict/words | while read -r word;
    do [ $word == `echo $word | rev` ] && echo $word;
done;

答案 1 :(得分:2)

多个grep是浪费的。你可以简单地做

grep -E '^([a-z])[a-z]\1$' /usr/share/dict/words

一举,同样地,将表达式放在grep的标准输入上,如下所示:

echo '^([a-z])[a-z]\1$
^([a-z])([a-z])\2\1$
^([a-z])([a-z])[a-z]\2\1$' | grep -E -f - /usr/share/dict/words

但是,常规grep不允许超出\9的反向引用。使用grep -P,您也可以使用两位数的反向引用。

以下脚本在循环中构造整个表达式。不幸的是,grep -P不允许使用-f选项,因此我们构建了一个大的thumpin'变量来保存模式。然后我们实际上也可以简化为^(.)(?:.|(.)(?:.|(.)....\3)?\2?\1$形式的单一模式,除了我们使用[a-z]代替.来限制为小写。

head=''
tail=''
for i in $(seq 1 22); do
    head="$head([a-z])(?:[a-z]|"
    tail="\\$i${tail:+)?}$tail"
done
grep -P "^${head%|})?$tail$" /usr/share/dict/words

单个grep应该比在大输入文件上单独调用grep 22或43次快得多。如果要按长度排序,只需将其添加为管道末尾的过滤器;它应该比整个字典上的多次传递更快。

表达式${tail+:)?}仅在tail非空时评估为右括号和问号,这是强制\1反向引用为非的方便方法可选的。有点类似,${head%|}$head的最终值修剪最终的交替运算符。

答案 2 :(得分:2)

为什么要使用grep? Bash很高兴为你做到这一点:

#!/bin/bash

is_pal() {
    local w=$1
    while (( ${#w} > 1 )); do
        [[ ${w:0:1} = ${w: -1} ]] || return 1
        w=${w:1:-1}
    done
 }

 while read word; do
     is_pal "$word" && echo "$word"
 done

将其另存为bananachmod +x banana并享受:

./banana < /usr/share/dict/words

如果您只想保留至少包含三个字符的字词:

grep ... /usr/share/dict/words | ./banana

如果您只想保留仅包含小写且至少包含三个字母的单词:

grep '^[[:lower:]]\{3,\}$' /usr/share/dict/words | ./banana

答案 3 :(得分:0)

好的,这是让你入门的事情:

我建议您使用上面的计划,只需生成“。”的数量。使用for循环。

这个问题将解释如何从3到45进行for循环:

How do I iterate over a range of numbers defined by variables in Bash?

for i in {3..45}; 
do 
   * put your code above here *
done

现在你只需要弄清楚如何制作“i”点数“。”在你的第一个grep中,你就完成了。

另外,看看sed,它可以为你编写非小写的答案..

答案 4 :(得分:0)

另一个使用Perl兼容正则表达式(PCRE)和递归的解决方案,严重this answer的启发:

grep -P '^(?:([a-z])(?=[a-z]*(\1(?(2)\2))$))++[a-z]?\2?$' /usr/share/dict/words