AWKで正規表現の欲を減らすには?

AWKで正規表現の欲を減らすには?

私はこれを理解しようとしていますawk。例は次のとおりです。

echo "@article{gjn, Author =   {Grzegorz J. Nalepa}, " | awk '{ sub(/@.*,/,""); print }'

短い文字列を選択する正規表現を作成できますか?

@article{gjn,

この長い文字列の代わりに? :

@article{gjn, Author =   {Grzegorz J. Nalepa},

私はこの結果を得たいと思います:

 Author =   {Grzegorz J. Nalepa},



別の例があります。

エコ」記事 {gjn, 著者 = {Grzegorz J. Nalepa}, " | awk '{ sub(/[^,]*,/,"");印刷}'
      ↑^^^^^^

入力文字列と正規表現の最初の位置にある文字を@コンマ()文字に変更しました。短い文字列を選択する正規表現を作成できますか?,.*[^,]*

, Author =   {Grzegorz J. Nalepa},

長い文字列の代わりに? :

,article{gjn, Author =   {Grzegorz J. Nalepa},

私はこの結果を得たいと思います:

,article{gjn

答え1

これ以降の@最初の項目を選択するには、,次のように指定する必要があります。@[^,]*,

その後にはカンマではなく@数字()が続き、その後にコンマ()が続きます。*[^,],

この方法は同じように機能しますが、後に続く内容が1つ以上の文字であるため、@.*?,同様の操作では機能しません。@.*?stringキャラクターを否定するのは簡単ですが、正規表現で文字列を否定することははるかに困難です。

別のアプローチは、入力を前処理して、string入力に現れない文字に置き換えるか、または前に追加することです。

gsub(/string/, "\1&") # pre-process
gsub(/@[^\1]*\1string/, "")
gsub(/\1/, "") # revert the pre-processing

入力に代替文字(\1上記)が含まれていないことを保証できない場合、1つのアプローチはエスケープメカニズムを使用することです。

gsub(/\1/, "\1\3") # use \1 as the escape character and escape itself as \1\3
                   # in case it's present in the input
gsub(/\2/, "\1\4") # use \2 as our maker character and escape it
                   # as \1\4 in case it's present in the input
gsub(/string/, "\2&") # mark the "string" occurrences

gsub(/@[^\2]*\2string/, "")

# then roll back the marking and escaping
gsub(/\2/, "")
gsub(/\1\4/, "\2")
gsub(/\1\3/, "\1")

これは固定sでは機能しますが、任意の正規表現stringでは機能しません。@.*?foo.bar

答え2

解決策を提供するいくつかの良い答えがすでにあります。awk貪欲ではないマッチングを実行できないことに対するいくつかの良い答えがすでにあります。Perl互換正規表現(PCRE).ほとんどの単純な「一致と印刷」スクリプトはawk簡単にperl使用でき-n、より複雑なスクリプトは次のように変換できます。a2pPerlの翻訳者には子供がいません。

真珠PerlスクリプトとPCREを使用するすべてのもので利用できる貪欲な演算子があります。たとえば、GNU grepオプションでも実装されています-P

PCREは同じではないPerlの正規表現に似ていますが、非常に似ています。これは非常に高速で、Perlの拡張正規表現拡張機能が非常に便利なため、多くのプログラムの正規表現ライブラリとして広く選択されています。

~からペレ(1)マニュアルページ:

   By default, a quantified subpattern is "greedy", that is, it will match
   as many times as possible (given a particular starting location) while
   still allowing the rest of the pattern to match.  If you want it to
   match the minimum number of times possible, follow the quantifier with
   a "?".  Note that the meanings don't change, just the "greediness":

       *?        Match 0 or more times, not greedily
       +?        Match 1 or more times, not greedily
       ??        Match 0 or 1 time, not greedily
       {n}?      Match exactly n times, not greedily (redundant)
       {n,}?     Match at least n times, not greedily
       {n,m}?    Match at least n but not more than m times, not greedily

答え3

これは古い記事ですが、次の情報は他の人に役立ちます。

awkで貪欲ではないREマッチングを実行する方法があります。デフォルトのアイデアは、match(string、RE)関数を使用し、一致が失敗するまで(テストされていない)次のように文字列サイズを徐々に減らすことです。

if (match(string, RE)) {
    rstart = RSTART
    for (i=RLENGTH; i>=1; i--)
        if (!(match(substr(string,1,rstart+i-1), RE))) break;
    # At this point, the non-greedy match will start at rstart
    #  for a length of i+1
}

答え4

awkでは、貪欲ではないマッチングを実行する方法はありません。しかし、所望の結果を得ることもできる。 schの提案がその行に適用されます。コンマに頼ることはできませんが、「作成者」が常に目的の内容の先頭にある場合は、次のようにできます。

awk '{ sub(/@.*Author/,"Author"); print }'

Author の前の文字数が常に同じであれば、次のことができます。

awk '{ sub(/@.{21}/,""); print }'

データセット全体でデータがどのように見えるかを知る必要があります。

関連情報