排除可能以斜杠结尾或可能不以斜杠结尾的单词

exclude words those may or may not end with slash

提问人:shantanuo 提问时间:12/3/2022 最后编辑:shantanuo 更新时间:12/7/2022 访问量:93

问:

我正在尝试从字典文件中排除某些单词。

# 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)。但“批次”一词是另一个词,不应与“批次”匹配。

与语言无关的 RG

评论

0赞 TLP 12/3/2022
grep -w似乎需要整字匹配,你试过吗?
0赞 Ed Morton 12/4/2022
你能有一条像 in 一样的线吗?如果是这样,应该输出还是不给出您发布的?可以包含任何单个字母,例如出现在 ?foo/batchen.txtexlude.txtexclude.txtnbatch/n
0赞 shantanuo 12/4/2022
如果 en.txt 中有一个单词“test/batch”,则不应将其包含在结果中。排除 .txt 文件只有没有 (hunspell) 标签的单词。
0赞 shantanuo 12/4/2022
@TLP尝试了 -w 参数。但这并没有返回正确的结果,因为我的文件包含 unicode 字符并且 grep 不完全兼容。
1赞 TLP 12/4/2022
@shantanuo 这可能是在您的问题中提供的相当重要的信息。为什么要排除它?

答:

2赞 Daweo 12/3/2022 #1

我会利用 GNU 来完成这个任务,让内容成为AWKen.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/FSFNR==NRarrnext!arr

(在 GNU Awk 5.0.1 中测试)

1赞 zdim 12/3/2022 #2

由于字典中有许多单词可能在其中一个要排除的单词中具有词根,因此我们不能方便†地使用查找哈希(由排除列表构建),而必须检查所有单词。更有效的一种方法是使用从排除列表构建的交替模式

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])?np(?:[^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;
}

在大型词典和一长串排除词上,这将更有效率。

但是,它要复杂得多,并且可能无法满足某些(未说明的)要求

1赞 The fourth bird 12/3/2022 #3

使用 grep 匹配整字:

grep -wvf exclude.txt en.txt

解释(来自man grep)

  • -w --word-regexp仅选择那些包含构成整个单词的匹配项的行。
  • -v --invert-match反转匹配感,选择不匹配的线条。
  • -f -f FILE从 FILE 获取模式,每行一个。

输出

testing
access/p
batches
cross

评论

1赞 shantanuo 12/4/2022
tried -w 参数。但这并没有返回正确的结果,因为我的文件包含 unicode 字符并且 grep 不完全兼容。但是 rg (ripgrep) 似乎按预期工作。我在询问时没有提到非拉丁字符,因为我认为这不会有任何区别。