提问人:shantanuo 提问时间:12/3/2022 最后编辑:shantanuo 更新时间:12/7/2022 访问量:93
排除可能以斜杠结尾或可能不以斜杠结尾的单词
exclude words those may or may not end with slash
问:
我正在尝试从字典文件中排除某些单词。
# cat en.txt
test
testing
access/p
batch
batch/n
batches
cross
# cat exclude.txt
test
batch
# grep -vf exclude.txt en.txt
access/p
cross
结果中应包含“测试”和“批次”等词。
expected result:
testing
access/p
batches
cross
因为单词“batch”后面可能跟着斜杠“/”,也可能不跟斜杠“/”。斜杠后可以有一个或多个标记(在本例中为 n)。但“批次”一词是另一个词,不应与“批次”匹配。
答:
我会利用 GNU 来完成这个任务,让内容成为AWK
en.txt
test
testing
access/p
batch
batch/n
batches
cross
和内容是exclude.txt
test
batch
然后
awk 'BEGIN{FS="/"}FNR==NR{arr[$1];next}!($1 in arr)' exclude.txt en.txt
给出输出
testing
access/p
batches
cross
解释:我通知GNU是字段分隔符(),然后在处理第一个文件时(其中全局行数等于文件内的行数,即)我只是使用第一列值作为数组中的键,然后转到行,所以没有其他事情发生,对于第二列(以及以下文件,如果存在)我选择第一列不是数组键之一的行。AWK
/
FS
FNR==NR
arr
next
!
arr
(在 GNU Awk 5.0.1 中测试)
由于字典中有许多单词可能在其中一个要排除的单词中具有词根,因此我们不能方便†地使用查找哈希(由排除列表构建),而必须检查所有单词。更有效的一种方法是使用从排除列表构建的交替模式
use warnings;
use strict;
use feature 'say';
use Path::Tiny; # to read ("slurp") a file conveniently
my $excl_file = 'exclude.txt';
my $re_excl = join '|', split /\n/, path($excl_file)->slurp;
$re_excl = qr($re_excl);
while (<>) {
if ( m{^ $re_excl (?:/.)? $}x ) {
# say "Skip printing (so filter out): $_";
next;
}
say;
}
这被用作并打印过滤后的列表。program.pl dictionary-filename
在这里,我假设可能在要排除的词根后面跟着一个字符,因为问题中的示例使用了这个字符,并且没有精确的陈述。该模式还假定单词周围没有空格。/
(?:/.)?
请根据需要进行调整,以实际可能发生的情况。例如,它至少适用于一个字符,适用于特定列表中的任何字符(或),适用于不在给定列表中的任何字符,等等。/
(?:/.+)?
(?:/[np])?
n
p
(?:[^xy]+)?
qr 运算符形成适当的正则表达式模式。
†仍然可以先去掉非单词结尾,然后使用查找,然后放回这些结尾
use Path::Tiny; # to read a file conveniently
my %lu = map { $_ => 1 } path($excl_file)->lines({ chomp => 1 });
while (<>) {
chomp;
# [^\w-] protects hyphenated words (or just use \W)
# Or: s{(/.+$}{}g; if "/" is the only possibility
s/([^\w-].+)$//g;
next if exists $lu{$_};
$_ .= $1 if $1;
say;
}
在大型词典和一长串排除词上,这将更有效率。
但是,它要复杂得多,并且可能无法满足某些(未说明的)要求
使用 grep 匹配整字:
grep -wvf exclude.txt en.txt
解释(来自man grep)
-w
--word-regexp
仅选择那些包含构成整个单词的匹配项的行。-v
--invert-match
反转匹配感,选择不匹配的线条。-f
-f FILE
从 FILE 获取模式,每行一个。
输出
testing
access/p
batches
cross
评论
grep -w
似乎需要整字匹配,你试过吗?foo/batch
en.txt
exlude.txt
exclude.txt
n
batch/n