最初の単語に特定の文字セットを含む行を見つける

最初の単語に特定の文字セットを含む行を見つける

入力ファイルは、複数の10文字の組み合わせを含む行の外側にあります。

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM
NCNREDEEEQ EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

最初の単語に「REGEX」という単語を構成する文字を含むすべての行を見つけるには、正規表現(PCREまたはBRE / ERE)が必要です。したがって、行の最初の単語には少なくともR 1、E 2、G 1、X 1が含まれている必要があります。

したがって、上記の結果は次のようになります。

NGNAEAREAX EAHVSELYCI FNWGNLACQM AWKLRMDHIT PRYMFNYMVM

答え1

単一の正規表現と一致させることはできません(*)。最終的な真または偽の結果を得るには、各条件(R 1、E 2、G 1、X 1)を個別に論理的にANDして一緒にテストする必要があります。

たとえば、次のようにしますawk

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

(*) 次の代替項目を使用して正規表現を作成できます。すべて5文字(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/言語/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)同じ場所でE空白以外の部分を見てください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

ここで唯一の非効率性は、興味のない文字の頻度を計算することです。

関連情報