查找第一个单词包含一组特定字母的行

查找第一个单词包含一组特定字母的行

输入文件存在于包含多个 10 个字母组合的行之外:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM
NCNREDEEEQ EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

我需要一个正则表达式(PCRE 或 BRE/ERE)来查找第一个单词包含形成单词“REGEX”的字母的所有行。因此该行的第一个单词必须至少包含 1 个 R、2 个 E、1 个 G 和 1 个 X。

所以上面的输出将是:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

答案1

您不能(*)将其与单个正则表达式匹配。您需要分别测试每个条件(一个 R、两个 E、一个 G、一个 X),并将它们逻辑“与”在一起以获得最终的真或假结果。

例如使用awk

$ awk '$1 ~ /R/ && $1 ~ /E.*E/ && $1 ~ /G/ && $1 ~ /X/' inputfile.txt 
NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

(*) 好吧,您可以创建一个包含以下替换的正则表达式每一个这五个字母(R、E、G、E 和 X)的可能组合以不同的顺序出现,但这是不切实际的。


顺便说一句,如果您需要不区分大小写的匹配并且您正在使用 GNU awk:

$ awk -v IGNORECASE=1 '$1 ~ /R/ && $1 ~ /E.*E/ && $1 ~ /G/ && $1 ~ /X/' inputfile.txt 

或者在没有 GNU awk 的情况下不区分大小写:

$ awk '$1 ~ /[Rr]/ && $1 ~ /[Ee].*[Ee]/ && $1 ~ /[Gg]/ && $1 ~ /[Xx]/' inputfile.txt 

答案2

使用(以前称为 Perl_6)

~$ raku -e 'for lines() {my %h; for .words.[0].comb() { %h{$_}++ };  \
           .put if %h.keys.contains( "R" & "E" & "G" & "X") && %h<E> >= 2 };'  file

输入示例:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM
NCNREDEEEQ EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

示例输出:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

Raku 是 Perl 家族的一种编程语言。发布的问题似乎确实是一个键/值问题,Raku 非常适合它(注意:解决方案中没有正则表达式)。

简而言之,lines读入时,每行在空白处用 分隔,并取出words第一个单词。[0]第一个单词被comb编辑成单独的字母。

从这一点开始,每个字母都被输入到(之前声明的)%h散列中,随后该字母(由主题变量 表示$_)立即成为散列中的唯一字母,其值由已看到的key次数确定(因此加上-加)。key%h{$_}++

%h在代码中返回此时的哈希值(使用say %h.sort),您将看到以下内容:

(A => 3 E => 2 G => 1 N => 2 R => 1 X => 1)
(C => 1 D => 1 E => 4 N => 2 Q => 1 R => 1)

顶部代码解决方案的最终语句要求%h散列contains每个字母"R" & "E" & "G" & "X"作为键,并且散列的“ E”键的值为>= 2。如果找到,则返回整行(.put缩写为$_.put,其中$_代表输入行)。

https://docs.raku.org/language/hashmap
https://perlgeek.de/blog-en/perl-5-to-6/08-junctions.html
https://raku.org

答案3

您可以为此使用前瞻运算符:

grep -P '^\s*+(?=\S*R)(?=\S*E\S*E)(?=\S*G)(?=\S*X)'

在这里寻找:

  • ^匹配在行的开头
  • \s*+跳过(并且不回头)所有前导空格(如果有)
  • (?=\S*R)向前查看此位置是否有R以下任意数量的非空白字符。
  • (?=\S*E\S*E)向前查看同一位置的非空白Enon-whitespaces E
  • 你明白了。

答案4

这里有awk一个函数,可以计算任何单词的字符数,并首先使用该函数来处理查询单词(“REGEX”),然后处理输入的第一个字段中的每个单词。然后,它检查第一个字段单词中的字符数是否足以生成查询单词,如果是,则打印该单词。

awk -v word="REGEX" '
    function calc(w,a) {
        for (i = 1; i <= length(w); ++i) a[substr(w,i,1)]++
    }
    BEGIN {
        # Character frequencies of the query word are stored in q.
        calc(word,q)
    }
    {
        # Get character frequencies for $1 and see if any
        # frequency in q are higher. If so, next.
        delete f; calc($1,f)
        for (ch in q) if (f[ch] < q[ch]) next
        print $1
    }' file

在问题的输入上运行它会输出NGNAEAREAX.

这里唯一的低效率是我们计算我们不感兴趣的字符的频率。

相关内容