web-dev-qa-db-ja.com

awk regexでregexグループを参照するにはどうすればよいですか?

Awk regexで正規表現グループを参照するにはどうすればよいですか?たとえば、正規表現グループ(\w)がある場合、(\w)\1のように同じ正規表現で後でそれをどのように参照できますか? awkはこの機能をサポートしていますか?以下の例は機能しません。

# In this example, I want to change aa to aaa and cc to ccc.
echo ab aa cc de mn | gawk '{print gensub(/(\w)\1/, "\\1\\1\\1", "g")}'
# The result is: ab aa cc de mn
# The expected result is: ab aaa ccc de mn
7
Just a learner
$ echo ab aa cc de mn | Perl -pe 's/(\w)\1/\1\1\1/g'
ab aaa ccc de mn

時々、あなたはawkができないことがいくつかあるが、Perlはできることを受け入れる必要があります。

明るい面を言えば、awkを十分に使い、gensubを使用して後方参照を行いたい場合は、Perlがドドルであることがわかります。つまり、awkを記述できる場合は、Perlを記述できます。

11
cas

これは問題を超えているかもしれませんが、awkが後方参照をサポートしていない理由は、awkが常に使用されているためですreal正規表現、つまり、有限状態マシンによって再帰なしで実装できる正規表現。このような実装は、いかなる形式の後方参照もサポートできません(実装は単純ではありませんが、キャプチャグループをサポートできます)。

私が見るようにawkを使用するアイデアは、正規表現を使用して、時間とメモリの範囲が制限されていない一致と、それより複雑なものにはCのような完全な言語を使用することです。

逆に、Perl/pcre /などからの「正規表現」は、チューリングマシンでのみ実装できる再帰的なマッチング手順を記述するコンパクトな構文に成長しました。これはセキュリティに影響します。信頼できないユーザーがそのような正規表現を入力できる検索ボックスなどは、サービス拒否攻撃への招待です。そのような試合にかかる時間やメモリを誰も知ることはできず、ハードな任意の制限や永続的な豚の禁止などの総計のみが可能です。

以下は、Russ Coxによる 古い記事 です。ここでは、これらすべてについて詳しく説明しています。

5
mosvy

正規表現ではありませんが、動作します。 Wordのすべての文字が同じである場合、1文字追加します。

echo ab aa cc de mn | \
      awk '{
        for(i=1;i<=NF;i++)
        {
          char=substr($i,1,1)
          for(j=2;j<=length($i);j++)
          {
            if(substr($i,j,1)==char) y=1
          else
            y=0
            char=substr($i,j,1)
          }
          if(y) $i=$i""char
        }
        print $0
        }'

    ab aaa ccc de mn         #output
1
zabidima

残念ながら、POSIXまたは他の非ビジーボックスawkでは、正規表現内では後方参照がサポートされていないため、各行のすべての一意の文字でループを必要とします。

$ cat tst.awk
{
    old = new = $0
    while (old != "") {
        char = substr(old,1,1)
        gsub(char,"",old)
        if ( char ~ /[[:alnum:]_]/ ) {
            gsub(char char,char char char,new)
        }
    }
    print new
}

$ echo ab aa cc de mn | awk -f tst.awk
ab aaa ccc de mn

上記は、ターゲット文字がこの場合のように正規表現メタ文字でない場合に機能します。それらがREメタ文字である可能性がある場合は、gsub()の正規表現コンテキストで使用する前にエスケープする必要があります。 char"{2}" の代わりに char char必要に応じてgsub()正規表現で。

Busybox awkでこのタスクを実行する方法については、@ Stephaneの回答を参照してください。

0
Ed Morton