我正在尝试在 bash 中制作一个拼字游戏助手,当给定字符列表时,它会找到/usr/share/dict/words
文件中的所有单词。
例如,当给定字母时,a,c,r,t
该单词cart
将匹配
该单词car
也将匹配
该单词carat
将不是匹配
但是,如果a,a,c,r,t
给出
thencarat
就会匹配。
我试图找出是否可以仅使用grep
,我怀疑像这样的大括号扩展
{a,c,r,t}{a,c,r,t}
可能有助于生成所有可能的字母组合,但我却遇到了类似的错误
grep: aaac: No such file or directory
grep: aaar: No such file or directory
grep: aaat: No such file or directory
运行命令时
$ grep {a,c,r,t}{a,c,r,t}{a,c,r,t}{a,c,r,t} /usr/share/dict/words
当我使用像"{a,c,r,t}{a,c,r,t}"
or 这样的引号时"\{a,c,r,t\}\{a,c,r,t\}"
,大括号扩展根本不起作用
我知道上面的命令不应该作为拼字游戏助手,但错误仍然是相当意外的。该命令有什么问题以及如何修复它?另外,可以grep
用某种方式来制作拼字游戏助手吗?
答案1
正则表达式不是此类工作的最佳工具。我会做类似的事情:
perl -CLASD -lne '
BEGIN{$l0{$_}++ for (split "", shift)}
%l = %l0; for (split "") {next LINE unless $l{$_}--}
print' aacrt < /usr/share/dict/words
或者从那时起(至少在法语和英语中以及一些使用拉丁字母的其他语言),拼字游戏只有 26 个大写字母 A 到 Z(été 写作 ETE,cœur 写作 COEUR),而 GNU iconv
:
iconv -t us//TRANSLIT < /usr/share/dict/words |
perl -CLASD -lne '
BEGIN{$l0{$_}++ for (split "", uc shift)}
%l = %l0; for (split "", uc $_) {next LINE unless $l{$_}--}
print' croeu
或者以原始形式输出:
perl -CLASD -MText::Unidecode -lne '
BEGIN{$l0{$_}++ for (split "", uc shift)}
%l = %l0; for (split "", uc unidecode $_) {next LINE unless $l{$_}--}
print' croeu < /usr/share/dict/word
答案2
这里发生的事情是由 {a,c,r,t}{a,c,r,t}{a,c,r,t}{a,c,r,t}
您正在使用的 shell 扩展的。这意味着第一个 ( ) 是将搜索、等aaaa
的模式,就像您键入:grep
aaac
aaar
grep aaaa aaac aaar aaat aaca ..... /usr/share/dict/words
将搜索模式放在单引号中以防止发生这种情况:
grep '{a,c,r,t}{a,c,r,t}{a,c,r,t}{a,c,r,t}' /usr/share/dict/words
另一方面,我不确定您是否在这里使用正确的 grep 语法。我会用:
grep '[acrt][acrt][acrt][actr]' /usr/share/dict/words
它匹配 4 个字符的组合,正如 @mueh 评论的那样:
grep -xE '[acrt]{1,4}' /usr/share/dict/words
匹配这些字母的 1-4 个组合。
答案3
大括号的 Bash 扩展不会生成有效的排列,因为该集合包含具有相同字符重复和某些缺失字符的项目。
您需要的是一些将使用全部或部分字符的字谜工具。幸运的是,这样的工具已经作为标准 Linux 的一部分存在。它被称为一个。它用/ usr /共享/字典/单词作为其默认字典。
以下是如何使用它的示例。
首先定义这个函数(交互式即可):
$ mywords() { an -w "$1" -m 4 | awk '/^[a-z]*$/ {print length($0), $0}' | column; }
现在假设您有这些字母 ypltar。要查找全部或部分使用的有效字典单词:
$ mywords ypltar
6 partly 5 party 4 tray 4 tarp 4 pray 4 part
6 paltry 5 aptly 4 trap 4 rapt 4 play 4 arty
我在函数中使用了 -m 4 将输出单词限制为不少于 4 个字母。您可以根据需要更改它。 awk 位用于排除带有大写字母的字典条目(专有名称等)。
答案4
所以,我玩这个让我生成了这个脚本,它给出了 3, ..., n 个字母的单词。它的问题在于字母可能会出现多次 - “WordGuess stop”将返回 oops 和 toot 以及 pots 和 post。仍在努力清理它。
#!/usr/bin/bash
# WordGuess - an attempt at automated word generation for
# anagrams and word finds
# 2024-02-02 SRJ
#
WordList="/usr/share/dict/american-english"
Argument="${@}"
Length=${#Argument}
# Double this to start properly with 3 character strings below
String="[${Argument}][${Argument}]"
for ((i = 2; i < ${Length}; i++)) ; do
String="${String}[${Argument}]"
echo -n $(grep -E "^${String}$" ${WordList})" "
echo
done
运行时;
WordGuess stop
ops opt pop pot sop sos sot too top tot tsp oops opts
poop pops poss post pots psst soot sops sots spot stop toot tops toss tost tots
我认为正确的方法是生成每个排列并尝试从单词列表中 grep ,但这会很慢。