使用grep -E
正则表达式,我需要查找包含一组不按特定顺序排列的所有字符的单词。例如,包含所有元音 (aeiou) 的单词,但元音可以以任何顺序出现在单词中。
答案1
该规则“以某种顺序包含所有内容aeiou
”无法用grep -E
合理大小的 POSIX 扩展正则表达式 ( ) 来表达。
这是一个大的列表,列出了 aeiou 的所有 120 种排列作为替代方案:
a.*e.*i.*o.*u|a.*e.*i.*u.*o|a.*e.*o.*i.*u|a.*e.*o.*u.*i|a.*e.*u.*i.*o|a.*e.*u.*o.*i|a.*i.*e.*o.*u|a.*i.*e.*u.*o|a.*i.*o.*e.*u|a.*i.*o.*u.*e|a.*i.*u.*e.*o|a.*i.*u.*o.*e|a.*o.*e.*i.*u|a.*o.*e.*u.*i|a.*o.*i.*e.*u|a.*o.*i.*u.*e|a.*o.*u.*e.*i|a.*o.*u.*i.*e|a.*u.*e.*i.*o|a.*u.*e.*o.*i|a.*u.*i.*e.*o|a.*u.*i.*o.*e|a.*u.*o.*e.*i|a.*u.*o.*i.*e|e.*a.*i.*o.*u|e.*a.*i.*u.*o|e.*a.*o.*i.*u|e.*a.*o.*u.*i|e.*a.*u.*i.*o|e.*a.*u.*o.*i|e.*i.*a.*o.*u|e.*i.*a.*u.*o|e.*i.*o.*a.*u|e.*i.*o.*u.*a|e.*i.*u.*a.*o|e.*i.*u.*o.*a|e.*o.*a.*i.*u|e.*o.*a.*u.*i|e.*o.*i.*a.*u|e.*o.*i.*u.*a|e.*o.*u.*a.*i|e.*o.*u.*i.*a|e.*u.*a.*i.*o|e.*u.*a.*o.*i|e.*u.*i.*a.*o|e.*u.*i.*o.*a|e.*u.*o.*a.*i|e.*u.*o.*i.*a|i.*a.*e.*o.*u|i.*a.*e.*u.*o|i.*a.*o.*e.*u|i.*a.*o.*u.*e|i.*a.*u.*e.*o|i.*a.*u.*o.*e|i.*e.*a.*o.*u|i.*e.*a.*u.*o|i.*e.*o.*a.*u|i.*e.*o.*u.*a|i.*e.*u.*a.*o|i.*e.*u.*o.*a|i.*o.*a.*e.*u|i.*o.*a.*u.*e|i.*o.*e.*a.*u|i.*o.*e.*u.*a|i.*o.*u.*a.*e|i.*o.*u.*e.*a|i.*u.*a.*e.*o|i.*u.*a.*o.*e|i.*u.*e.*a.*o|i.*u.*e.*o.*a|i.*u.*o.*a.*e|i.*u.*o.*e.*a|o.*a.*e.*i.*u|o.*a.*e.*u.*i|o.*a.*i.*e.*u|o.*a.*i.*u.*e|o.*a.*u.*e.*i|o.*a.*u.*i.*e|o.*e.*a.*i.*u|o.*e.*a.*u.*i|o.*e.*i.*a.*u|o.*e.*i.*u.*a|o.*e.*u.*a.*i|o.*e.*u.*i.*a|o.*i.*a.*e.*u|o.*i.*a.*u.*e|o.*i.*e.*a.*u|o.*i.*e.*u.*a|o.*i.*u.*a.*e|o.*i.*u.*e.*a|o.*u.*a.*e.*i|o.*u.*a.*i.*e|o.*u.*e.*a.*i|o.*u.*e.*i.*a|o.*u.*i.*a.*e|o.*u.*i.*e.*a|u.*a.*e.*i.*o|u.*a.*e.*o.*i|u.*a.*i.*e.*o|u.*a.*i.*o.*e|u.*a.*o.*e.*i|u.*a.*o.*i.*e|u.*e.*a.*i.*o|u.*e.*a.*o.*i|u.*e.*i.*a.*o|u.*e.*i.*o.*a|u.*e.*o.*a.*i|u.*e.*o.*i.*a|u.*i.*a.*e.*o|u.*i.*a.*o.*e|u.*i.*e.*a.*o|u.*i.*e.*o.*a|u.*i.*o.*a.*e|u.*i.*o.*e.*a|u.*o.*a.*e.*i|u.*o.*a.*i.*e|u.*o.*e.*a.*i|u.*o.*e.*i.*a|u.*o.*i.*a.*e|u.*o.*i.*e.*a
这是一个更短的代码,但由于嵌套而更难理解:
a.*(e.*(i.*[ou]|o.*[iu]|u.*[io])|i.*(e.*[ou]|o.*[eu]|u.*[eo])|o.*(e.*[iu]|i.*[eu]|u.*[ei])|u.*(e.*[io]|i.*[eo]|o.*[ei]))|e.*(a.*(i.*[ou]|o.*[iu]|u.*[io])|i.*(a.*[ou]|o.*[au]|u.*[ao])|o.*(a.*[iu]|i.*[au]|u.*[ai])|u.*(a.*[io]|i.*[ao]|o.*[ai]))|i.*(a.*(e.*[ou]|o.*[eu]|u.*[eo])|e.*(a.*[ou]|o.*[au]|u.*[ao])|o.*(a.*[eu]|e.*[au]|u.*[ae])|u.*(a.*[eo]|e.*[ao]|o.*[ae]))|o.*(a.*(e.*[iu]|i.*[eu]|u.*[ei])|e.*(a.*[iu]|i.*[au]|u.*[ai])|i.*(a.*[eu]|e.*[au]|u.*[ae])|u.*(a.*[ei]|e.*[ai]|i.*[ae]))|u.*(a.*(e.*[io]|i.*[eo]|o.*[ei])|e.*(a.*[io]|i.*[ao]|o.*[ai])|i.*(a.*[eo]|e.*[ao]|o.*[ae])|o.*(a.*[ei]|e.*[ai]|i.*[ae]))
这两者都假设您要搜索的单词位于每行一个单词的文件中。如果没有,您必须将所有的.
' 更改为[^ ]
匹配非空格字符。 (注意:\S
from perl 可在许多正则表达式引擎中使用,可能包括您使用的 grep,但与 perl 兼容的正则表达式不是标准 grep 功能,所以[^ ]
它必须是。)
我不会尝试手动编写这些正则表达式。我在第一个代码中使用了排列生成器,并在 vim 中进行了大量的宏录制和重放来编写第二个代码。
但让我们看看如果我们把问题倒过来会发生什么。不要尝试匹配包含所有元音的字符串,而是尝试匹配相反的字符串:至少缺少一个元音。
(从现在开始,我坚持输入中每行一个单词的假设。)
a
缺少匹配项的单词^[^a]*$
(从头到尾都是由 以外的字符组成a
)。
e
缺少匹配项的单词^[^e]*$
缺少i
匹配项的单词^[^i]*$
缺少匹配o
项的单词 缺少匹配项^[^o]*$
的单词u
^[^u]*$
a
缺少或缺少e
或缺少i
或缺少o
或缺少u
匹配项的单词
^([^a]*|[^e]*|[^i]*|[^o]*|[^u]*)$
所以这个 grep 命令会给你所有你不想要的单词:
grep -E '^([^a]*|[^e]*|[^i]*|[^o]*|[^u]*)$' wordlist
方便的-v
选项为您提供了您想要的单词做想:
grep -vE '^([^a]*|[^e]*|[^i]*|[^o]*|[^u]*)$' wordlist
如果需要的话添加-i
。
编写正则表达式时要记住反转技术。有时,一个非常复杂的正则表达式是一个简单正则表达式的逆。
答案2
是否需要成为一个单身的 grep
命令?要查找包含每个元音至少一次(以任何顺序)的所有单词,最简单的命令是
查询一个单词表| grep e | grep 我 | grep o |格列普你
-i
如果需要不区分大小写,请添加。
答案3
在我看来,这是一个有点棘手的问题,因为grep
它不具有真正的 AND 运算符。您可以使用各种技巧来grep
部分获得 AND,但它仅在某些情况下有效。
例如,您可以使用通配符运算符来匹配具有您的模式的字符串,但只有当它的顺序与您的模式完全相同时,它才会匹配它。
样本文件
$ cat words.txt
aeiou
a1e2i3o4u5
dog
blh
spkz
uoiea
1. 使用 .* 的示例
$ grep -E ".*a.*e.*i.*o.*u.*" words.txt
aeiou
a1e2i3o4u5
aeiou
这仅匹配具有同一级数中的序列的字符串。但它无法匹配uoiea
。
2. 使用 [aeiou] 的示例
$ grep -E [aeiou] words.txt
aeiou
a1e2i3o4u5
dog
uoiea
这种方法可以匹配,但它太松散,匹配任何包含我们模式中至少 1 个字母的内容。
3. 使用多个 grep 的示例
$ grep a words.txt | grep e | grep i | grep o | grep u
aeiou
a1e2i3o4u5
uoiea
如果您被迫使用grep
,并且您的目的是匹配一组中的所有字符,那么这实际上是您可用的唯一选项。
4. 使用 awk 的示例
$ awk '/a/ && /e/ && /i/ && /o/ && /u/ { print }' words.txt
aeiou
a1e2i3o4u5
uoiea
就像处理 Unix 时经常出现的情况一样。如果您愿意改用合适的工具,看似不可能的任务就会变得容易。通过切换到,awk
我们现在可以使用实际的 AND 运算符 ( &&
),现在我们可以指定要查找的字符集。
grep
5. 使用 的其他开关的示例(-w)
如果您匹配的字符串都保证是单个单词,您可以使用该-w
开关。
-w, --word-regexp
Select only those lines containing matches that form whole words.
The test is that the matching substring must either be at the
beginning of the line, or preceded by a non-word constituent
character. Similarly, it must be either at the end of the line or
followed by a non-word constituent character. Word-constituent
characters are letters, digits, and the underscore.
因此,只要该集合中的一系列字母[aeiou]
都是连续的,您就可以像这样利用此开关:
$ grep -Ew "*[aeiou]*" words.txt
aeiou
uoiea
但如果你必须处理多情况短语,那么它也会让你失败:
$ echo "I love Fort Lauderdale" | grep -Ew "*[aeiou]*"
$
但是,如果我们使用不区分-i
大小写的开关grep
,那么它将再次起作用:
$ echo "I love Fort Lauderdale" | grep -Ewi "*[aeiou]*"
I love Fort Lauderdale