Linux 使用grep从字典中删除词根已经存在的单词
我正在尝试编写一个随机密码短语生成器。我有一个包含大量单词的词典,我想删除词根已经在词典中的单词,这样一个词典看起来像:Linux 使用grep从字典中删除词根已经存在的单词,linux,bash,dictionary,grep,Linux,Bash,Dictionary,Grep,我正在尝试编写一个随机密码短语生成器。我有一个包含大量单词的词典,我想删除词根已经在词典中的单词,这样一个词典看起来像: ablaze able abler ablest abloom ably 结果只会是 ablaze able abloom ably 因为abler和ablest包含以前使用过的able 我更愿意和grep一起做这件事,这样我可以了解更多关于它是如何工作的。我能够用c或python编写一个程序来实现这一点。如果您想以共享相同前四个(最多十个)字母的单词开头,您可以这样做:
ablaze
able
abler
ablest
abloom
ably
结果只会是
ablaze
able
abloom
ably
因为abler和ablest包含以前使用过的able
我更愿意和grep一起做这件事,这样我可以了解更多关于它是如何工作的。我能够用c或python编写一个程序来实现这一点。如果您想以共享相同前四个(最多十个)字母的单词开头,您可以这样做:
cp /usr/share/dict/words words
str="...."
for num in 4 5 6 7 8 9 10; do
for word in `grep "^$str$" words`; do
grep -v "^$word." words > words.tmp
mv words.tmp words
done
str=".$str"
done
除非字典中没有“a”,否则您不希望以1个字母开头,等等。试试下面的BASH脚本:
a=()
while read -r w; do
[[ ${#a[@]} -eq 0 ]] && a+=("$w") && continue
grep -qvf <(printf "^%s\n" "${a[@]}") <<< "$w" && a+=("$w")
done < file
printf "%s\n" "${a[@]}"
ablaze
able
abloom
ably
a=()
而read-rw;做
[${a[@]}-eq 0]&&a+=(“$w”)&&continue
grep-qvf如果您只想删除一些单词,那么这个gross命令就可以了。注意,它会抛出一些像best这样的合法词语,但它非常简单。它假定您有一个test.txt文件,每行一个字
egrep-v“er$| est$”test.txt>>results.txt
egrep与grep-E
相同-v
表示抛出匹配行x | y
表示如果x或y匹配,$
表示行尾,因此您将查找以er或est结尾的单词这是基于输入文件已排序的假设。在这种情况下,当查找每个单词时,可以安全地跳过第一个单词之后的所有匹配项(因为它们将对应于“具有不同后缀的同一单词”)
似乎你想把副词组合在一起。一些副词,包括那些也可以是形容词的副词,使用er和est进行比较:
- 能干的,能干的,能干的
- 快,快,快
- 快,快,快
- 容易,容易,容易
import nltk
initial = '''
ablaze
able
abler
ablest
abloom
ably
fast
faster
fastest
'''.splitlines()
snowball = nltk.stem.snowball.SnowballStemmer("english")
stemmed = [snowball.stem(word) for word in initial]
print set(stemmed)
输出
set(['', u'abli', u'faster', u'abl', u'fast', u'abler', u'abloom', u'ablest', u'fastest', u'ablaz'])
set(['', 'abloom', 'able', 'abl', 'fast', 'ably', 'ablaze'])
另一种选择是使用regex词干分析器,但恐怕这也有它自己的困难
patterns = "er$|est$"
regex_stemmer = nltk.stem.RegexpStemmer(patterns, 4)
stemmed = [regex_stemmer.stem(word) for word in initial]
print set(stemmed)
输出
set(['', u'abli', u'faster', u'abl', u'fast', u'abler', u'abloom', u'ablest', u'fastest', u'ablaz'])
set(['', 'abloom', 'able', 'abl', 'fast', 'ably', 'ablaze'])
如果对列表进行排序,使较短的字符串始终位于较长的字符串之前,则可以通过简单的Awk脚本获得相当好的性能
awk '$1~r && p in k { next } { k[$1]++; print; r= "^" $1; p=$1 }' words
如果当前单词与前缀regexr
(在片刻中定义)匹配,并且前缀p
(同上)在可见键列表中,则跳过。否则,将当前单词添加到前缀键中,打印当前行,创建一个与行首当前单词匹配的正则表达式(现在是前缀正则表达式r
),并记住p
中的前缀字符串
如果所有相似的字符串总是相邻的(如果按词汇对文件进行排序,它们就会是相邻的),那么我想您也可以完全取消k
和p
awk 'NR>1 && $1~r { next } { print; r="^" $1 }' words
你试过什么?你得到了什么?。现在,你的问题似乎是“为我写这个程序,这样我就可以从中学习”-请展示一些研究成果。@tucuxi很好。我真的很想看到有人在grep中这样做,因为我能够在c或python中这样做。我更新了问题以反映这一点。我认为这比你想象的要复杂得多。盲目删除以“est”、“er”等结尾的单词是一回事,而不是知道这两个单词是相关的。如果出现像鹅对鹅这样的词,你会怎么做?或者两个相似但不相关的单词呢?例如doner vs doner?@user1146334我很乐意离开geese并删除doner(虽然doner不在字典中,但tone和toner有相同的问题)。我不想编制一份英语词根列表,只想删除那些会使正确的密码短语更难记住的后缀(是正确的吗?纠正了吗?纠正了吗?马?马?)。添加了一个概念验证答案。尽管我会推荐Python(或几乎任何其他东西)而不是Bash来进行文本处理,但我是否遗漏了什么?此脚本不在任何地方使用$num。它不需要$num的值,因为每次都会增加长度$str。更重要的是让用户知道发生了什么。它本可以这样写:
用于代码>(等等)我现在明白了。谢谢。我在对原始问题的评论中提到,我并没有试图编译一个根单词列表,只是删除了可能使随机单词组合更难记住的东西(我也可以用python解决这个问题,但我正在寻找一个直接的grep解决方案)。不过,谢谢你的建议。我第一次尝试堆栈溢出的错误答案,但我甚至没有阅读问题:0。吸取的教训。事实上,“best”是一个最高级,所以它实际上可能是一个有效的目标,但这也会过滤掉“test”、“best”和“father”。对于任何实际使用来说,可能过于简单化了。这比我尝试遍历文件的速度要快得多。即使有2万个单词,在完整的美式英语
文件中也只花了不到一分钟的时间。使用--mmap
标志没有多大区别。免责声明:我有一个SSD。我的字典是小写的美式英语单词,有超过4个字母[a-z],没有撇号。做得很好。建议:将&&continue
附加到具有第一个条件(..-eq 0…
)的行,这允许您从下一行删除条件(..-gt 0…
)。@mklement0:感谢您的建议。编辑了它。很高兴听到它-谢谢编辑。现在可以从循环体的第2行中删除[[${a[@]}-gt 0]&&
,在