Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 使用grep从字典中删除词根已经存在的单词_Linux_Bash_Dictionary_Grep - Fatal编程技术网

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
表示如果xy匹配,
$
表示行尾,因此您将查找以er或est结尾的单词这是基于输入文件已排序的假设。在这种情况下,当查找每个单词时,可以安全地跳过第一个单词之后的所有匹配项(因为它们将对应于“具有不同后缀的同一单词”)


似乎你想把副词组合在一起。一些副词,包括那些也可以是形容词的副词,使用er和est进行比较:

  • 能干的,能干的,能干的
  • 快,快,快
  • 快,快,快
  • 容易,容易,容易
这个过程在自然语言处理中称为词干分析,可以使用词干分析器或lemmatizer实现。python的NLTK模块中有一些流行的实现,但问题并没有完全解决。最好的现成词干分析器是snowball词干分析器,但它不会将副词词干到词根

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
如果当前单词与前缀regex
r
(在片刻中定义)匹配,并且前缀
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]&&
,在