包装 hunspell 以有效地阻止大量单词?
Wrapping hunspell to stem a large number of words efficiently?
我写了一个提取英语单词的脚本,它做得不错,但是当我在大文件上使用它时,它需要很长时间,这些文件有超过 1000 个单词,每行一个。有没有办法加快速度?也许完全不同的方法?不同的编程语言?不同的词干分析器?
file=
while read -r a
do
b="$(echo "$a" | hunspell -s -d en_US | wc -l)"
if [[ "$b" -eq 2 ]]
then
g="$(echo "$a" | hunspell -s -d en_US | wc -w)"
if [[ "$g" -eq 1 ]]
then
echo "$a" | hunspell -s -d en_US | awk 'FNR==1 {print }'
else
echo "$a" | hunspell -s -d en_US | awk 'FNR==1 {print }'
fi
else
if [[ "$a" == *ing ]] || [[ "$a" == *ed ]]
then
echo "$a" | hunspell -s -d en_US | awk 'FNR==2 {print }'
else
echo "$a" | hunspell -s -d en_US | awk 'FNR==1 {print }'
fi
fi
done < "$file"
这是它的作用的一个例子。
输入文件
cliché
womb
range
strain
fiddle
coup
earnest
touched
gave
dazzling
blindfolded
stagger
buying
insignia
输出
cliché
womb
range
strain
fiddle
coup
earnest
touch
give
dazzle
blindfold
stagger
buy
insignia
工作原理
如果你运行hunspell -s -d en_US word
,它可以根据一个词给你不同的结果。选项和要采取的行动如下:
- 一行一个字(打印那个字)
- 一行两字(打印第二个字)
- 两行两字;以 "ing" 或 "ed" 结尾(在第二行打印第二个单词)
- 两行两字;不以 "ing" 或 "ed" 结尾(在第一行打印第一个字)
以下发出完全相同的输出(但将 gave
更改为 give
,我的 hunspell
似乎在其字典中没有)——而且快得多:
last_word=; stems=( )
while read -r word stem _; do
if [[ $word ]]; then
last_word=$word
[[ $stem ]] && stems+=( "$stem" )
else
if (( ${#stems[@]} == 0 )); then
printf '%s\n' "$last_word" # no stems available; print input word
elif (( ${#stems[@]} == 1 )); then
printf '%s\n' "${stems[0]}" # found one stem; print it.
else
case $last_word in
*ing|*ed) printf '%s\n' "${stems[1]}" ;; # "ing" or "ed": print the 2nd stem
*) printf '%s\n' "${stems[0]}" ;; # otherwise: print the 1st stem
esac
fi
stems=( )
fi
done < <(hunspell -s -d en_US <"")
请注意,这 hunspell
对整个文件只运行一次 ,而不是每个单词运行一次;它一遍又一遍地重新启动 hunspell
,与 bash 没有任何关系,您的脚本一直在其中花费时间。
我写了一个提取英语单词的脚本,它做得不错,但是当我在大文件上使用它时,它需要很长时间,这些文件有超过 1000 个单词,每行一个。有没有办法加快速度?也许完全不同的方法?不同的编程语言?不同的词干分析器?
file=
while read -r a
do
b="$(echo "$a" | hunspell -s -d en_US | wc -l)"
if [[ "$b" -eq 2 ]]
then
g="$(echo "$a" | hunspell -s -d en_US | wc -w)"
if [[ "$g" -eq 1 ]]
then
echo "$a" | hunspell -s -d en_US | awk 'FNR==1 {print }'
else
echo "$a" | hunspell -s -d en_US | awk 'FNR==1 {print }'
fi
else
if [[ "$a" == *ing ]] || [[ "$a" == *ed ]]
then
echo "$a" | hunspell -s -d en_US | awk 'FNR==2 {print }'
else
echo "$a" | hunspell -s -d en_US | awk 'FNR==1 {print }'
fi
fi
done < "$file"
这是它的作用的一个例子。
输入文件
cliché
womb
range
strain
fiddle
coup
earnest
touched
gave
dazzling
blindfolded
stagger
buying
insignia
输出
cliché
womb
range
strain
fiddle
coup
earnest
touch
give
dazzle
blindfold
stagger
buy
insignia
工作原理
如果你运行hunspell -s -d en_US word
,它可以根据一个词给你不同的结果。选项和要采取的行动如下:
- 一行一个字(打印那个字)
- 一行两字(打印第二个字)
- 两行两字;以 "ing" 或 "ed" 结尾(在第二行打印第二个单词)
- 两行两字;不以 "ing" 或 "ed" 结尾(在第一行打印第一个字)
以下发出完全相同的输出(但将 gave
更改为 give
,我的 hunspell
似乎在其字典中没有)——而且快得多:
last_word=; stems=( )
while read -r word stem _; do
if [[ $word ]]; then
last_word=$word
[[ $stem ]] && stems+=( "$stem" )
else
if (( ${#stems[@]} == 0 )); then
printf '%s\n' "$last_word" # no stems available; print input word
elif (( ${#stems[@]} == 1 )); then
printf '%s\n' "${stems[0]}" # found one stem; print it.
else
case $last_word in
*ing|*ed) printf '%s\n' "${stems[1]}" ;; # "ing" or "ed": print the 2nd stem
*) printf '%s\n' "${stems[0]}" ;; # otherwise: print the 1st stem
esac
fi
stems=( )
fi
done < <(hunspell -s -d en_US <"")
请注意,这 hunspell
对整个文件只运行一次 ,而不是每个单词运行一次;它一遍又一遍地重新启动 hunspell
,与 bash 没有任何关系,您的脚本一直在其中花费时间。