我有一个包含单词列表的文件。我想从一个大文本文件中删除此文件中所有单词的所有出现。
例子:
文件1
queen
king
文本文件样本
Both the king and queen are monarchs. Will the queen live? Queen, it is!
这是我尝试过的:
sed -i 's/queen/ /g' page.txt
sed -i 's/Queen/ /g' page.txt
输出
Both the and are monarchs. Will the live? , it is!
我的单词列表很大(超过 50000 个单词)。如何在无需在命令行中指定模式的情况下执行此操作?
答案1
对于您的实际用例,我建议terdon 使用 Perl 的回答。
然而,简单的版本,不处理其他单词的子串(例如,从“hiking”中删除“king”),是使用一个 Sed 命令生成由不同 Sed 实例运行的命令在您的实际文件上。
在这种情况下,wordfile
包含“国王”和“女王”并textfile
包含您的文本:
sed -e "$(sed 's:.*:s/&//ig:' wordfile)" textfile
请注意,“i
忽略大小写”标志是 GNU 扩展,而不是标准。
答案2
简单但低效的方法是多次处理文件,每个输入单词处理一次:
$ while read w; do sed -i "s/$w//ig" file2 ; done < file1
$ cat file2
Both the and are monarchs. Will the live? , it is!
不过,对于大文件来说,这可能会非常慢(并且还匹配子字符串)。您可以使用 Perl 一次性完成此操作:
perl -lpe 'BEGIN{open(A,"file1"); chomp(@k = <A>)}
for $w (@k){s/\b\Q$w\E\b//ig}' file2
确保\b
我们只匹配单词边界,\Q\E
确保$w
按字面意思理解。这将阻止脚本匹配hiking
,但它仍然会匹配high-king
。为了避免这种情况,您需要明确列出定义单词的字符:
perl -Mopen=locale -Mutf8 -lpe '
BEGIN{open(A,"file1"); chomp(@k = <A>)}
for $w (@k){s/(^|[ ,.—_;-])\Q$w\E([ ,.—_;-]|$)/$1$2/ig}' file2
上面的非 ASCII字符—
需要以 UTF-8 编码形式输入,因为我们告诉perl
代码是用 UTF-8 编写的-Mutf8
。我们使用-Mopen=locale
文件的内容和标准输出在区域设置的字符集中进行解码/编码。
答案3
将此脚本保存到文件d
:(从 GITHUB 下载 GIST)
#!/bin/bash
LIST=${1:?"LIST word"}
FILE=${2:?"FILE name not set"}
L=$( sed -e ':a;N;$!ba;s_\n_\x00_g' ${LIST}|sed -e 's_\x00_ \\|_g' -e's_\(\\|\)*$__g')
P='s_\('$L'\)__ig'
O="sed -e '$P' ${FILE}"
eval "${O}"
然后运行它:
bash ./d LIST FILE
如果你想保存文件,你可以运行这个命令:
bash ./d LIST FILE | tee NewFILE
或者
bash ./d LIST FILE > NewFile
我阅读 LIST WORD 并将其更改为正则表达式格式,例如我将您的queen
andking
更改test
为以下格式:
queen\|king\|test
然后sed
使用此参数创建命令:
sed -e 's_\(queen\|king\|test\) *__ig' FILE
使用这个 bash 脚本,我们一次LISTWORD
又一次地读取FILE
以进行替换