1

The input file exists out of lines containing multiple 10-letter combinations:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM
NCNREDEEEQ EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

I need a regex (PCRE or BRE/ERE) that finds all lines of which the first word contains the letters to form the word "REGEX". So the first word of the line has to contain at least 1 R, 2 E's, 1 G and 1 X.

So the output of the above would be:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM
3
  • What have you tried? Oct 21, 2022 at 23:05
  • 1
    @NasirRiley I've tried '^.?.?.?.?.?([SATN].?.?){5,} .*' but I don't think doing it that way is viable.
    – Tomyy
    Oct 21, 2022 at 23:18
  • What exact commands including the syntax did you try? What was the output including any error messages? Add all of this information to the question. Oct 22, 2022 at 0:44

4 Answers 4

3

You can't(*) match this with a single regex. You need to test each condition (one R, two Es, one G, one X) separately and logically AND them together to get a final true or false result.

e.g. using awk:

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

(*) well, you could create a regex containing alternations for every possible combination of those five letters (R, E, G, E again, and X) appearing in different order but that isn't practical.


BTW, if you need case-insensitive matches and you're using GNU awk:

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

or case-insensitive without GNU awk:

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

Using Raku (formerly known as 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

Sample Input:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM
NCNREDEEEQ EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

Sample Output:

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

Raku is a programming language in the Perl-family. The problem as posted really seems to be a key/value problem, for which Raku is well suited (notice: no regex in the solution).

Briefly, lines are read-in, each line is broken on whitespace with words, and the first word [0] is taken. This first word is combed into individual letters.

From this point each letter is fed into the (previously declared) %h hash, whereupon the letter (represented by topic variable $_) immediately becomes a unique key in the hash, with a value determined by the number of times that key has been seen (hence the %h{$_}++ plus-plus).

Returning the %h hash at this point in the code ( using say %h.sort ), you would see the following:

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

The final statement of the code solution at top demands that the %h hash contains each letter "R" & "E" & "G" & "X" as keys, and also that the value of the hash's "E" key is >= 2. If found, the entire line is returned (.put being short for $_.put, wherein $_ represents the input line).

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

0

You can use look ahead operators for that:

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

Here looking for:

  • ^ match at the start of the line
  • \s*+ skipping (and not looking back) all leading whitespace if any
  • (?=\S*R) look ahead at this spot for a R following any number of non-whitespace character.
  • (?=\S*E\S*E) look ahead at the same spot for non-whitespacesEnon-whitespacesE.
  • you get the gist.
0

Here's awk with a function that calculates the character counts of any word and that uses that function first to process the query word ("REGEX") and then each of the words from the first field of the input. It then checks whether the counts of characters in the 1st field word are enough to generate the query word and if so, the word is printed.

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

Running this on the input in the question would output NGNAEAREAX.

The only inefficiency here is that we calculate the frequencies of characters that we're uninterested in.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .