awk - 同じ行の直接パターンの後に一度交換してください!

awk - 同じ行の直接パターンの後に一度交換してください!

1.5MBファイルがあります。
1行には約160,000文字があります。
この行では、PATTERNの直後に「false」を「true」に一度変更するだけです。

awkの後、最初の発生のみが変更されます。
ただし、「PATTERN」以降は一度だけ変更してください。

awk '/PATTERN.*false/ {sub("false", "true")} {print}' file

私たちのファイルは次のとおりです。

...
colorA is false colorB is false PATTERN is false colorC is false colorD is false
...

ファイルには以下が必要です。

...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

必要に応じてawkコマンドをどのように配置しますか?

よろしくお願いします!

答え1

「false」と一致しない最短文字列に一致する正規表現を作成することは理論的に可能ですが、難しいです。他のさまざまな言語にはselect-shortest構文がありますが、awkはそのうちの1つではありません。

したがって、難しい表現を作成したくないと仮定すると、3つのアプローチがあります。

  1. 入力を「false」という単語に分割し、フィールドを繰り返して、現在のフィールドがパターンと一致する場合は「true」の後に印刷し、それ以外の場合は「false」の後に印刷できます。
  2. トリックを使用して、「false」のすべての項目をcontrol-aなどの未使用の単一文字に変換できます。これにより、正規表現は、最も短いモード制御で終わるものと一致するように[^\001]*\001と言えるように書くのは簡単です。 -ㅏ。
  3. フィールドを繰り返し、現在のフィールドがスキーマの場合はフラグを設定し、「false」、フラグが設定されている場合は「true」に変更し、フラグをリセットします。

方法3の場合。

#!/usr/bin/awk

/PATTERN.*false/ {
        for(i=1;i<=NF;i++) {
                if ($i ~ /PATTERN/) flag=1;
                if ($i == "false" && flag==1) {
                        $i="true"
                        flag=0
                }
        }
}
{print}

これにより、入力の空白が縮小されます。

答え2

PATTERN解決策は()で行分割を実装しsplit、最初の部分をfalse2番目の部分()で置き換え、その部分を結合します(ループ合計)。このコマンドはこの入力ラインの追加処理をスキップします。他の行は変更されずに印刷されます。 (デフォルトの動作がある場合は常に真の条件です。)subforprintfnext1

awk '/PATTERN.*false/ {
    n=split($0,parts,"PATTERN"); 
    sub("false", "true", parts[2]); 
    for(i=1;i<n;i++) {
        printf("%s%s", parts[i], "PATTERN");
    }
    printf("%s\n", parts[n]);
    next }
1'

PATTERNその値が常に存在するかどうかは質問で明確ではないため、代替エラーになる可能性falseがありますfalse

入力サンプル

colorA is false colorB is false PATTERN is false colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false

結果は次のとおりです。

colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is true colorD is false

編集する~によるとルーディック注:PATTERN以降に変更される値が「true」または「false」の場合、ディレクティブを次のように置き換えることでこのsub("false", "true", parts[2]);問題を回避できます。sub("false|true", "true", parts[2]);

awk '/PATTERN.*false/ {
    n=split($0,parts,"PATTERN"); 
    sub("false|true", "true", parts[2]); 
    for(i=1;i<n;i++) {
        printf("%s%s", parts[i], "PATTERN");
    }
    printf("%s\n", parts[n]);
    next }
1'

同じサンプル入力を使用すると、結果は次のようになります。

colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false

答え3

GNU awkを使用してmatch()とgensub()に3番目の引数を渡します。

$ awk 'match($0,/(.*PATTERN)(.*)/,a){$0=a[1] gensub(/false/,"true",1,a[2])} 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

そしていくつかの奇妙な:

$ awk 'match($0,/.*PATTERN/){tail=substr($0,RSTART+RLENGTH); sub(/false/,"true",tail); $0=substr($0,1,RSTART+RLENGTH-1) tail } 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

関連情報