パターン形状に基づいてファイルを編集する

パターン形状に基づいてファイルを編集する

次のテキストと数字を含むファイルがあります。

state(1, s(1,a), [s(1,b)]).
state(1, s(1,b), [s(1,a)]).
state(1, s(2,a), [s(2,b)]).
state(1, s(2,b), [s(2,a)]).
state(1, s(3,a), [s(3,b)]).
state(1, s(3,b), [s(3,a)]).
state(1, s(4,a), [t(1), t(2)]).
state(1, s(5,a), [t(1), t(3)]).
state(1, s(6,a), [s(6,b)]).
state(1, s(6,b), [s(6,a)]).
...so on

s(x,y) の数字を次のように変更したいと思います。

state(1, p(1), 0, [p(2)]).
state(1, p(2), 0, [p(1)]).
state(1, p(3), 0, [p(4)]).
state(1, p(4), 0, [p(3)]).
state(1, p(5), 0, [p(6)]).
state(1, p(6), 0, [p(5)]).
state(1, p(7), -1, [t(1), t(2)]).
state(1, p(8), -1, [t(1), t(3)]).
state(1, p(9), 0, [p(10)]).
state(1, p(10), 0, [p(9)]).
...so on

状態の3番目のパラメータの0と-1は、単にss(またはpp)接続の存在/存在(0と表示)または接続の欠如(-1と表示)を表します。

私は「sed」を試しましたが、まったく成功しませんでした。

いくつかのヒントや回避策を得ることができますか?

答え1

シェルループの代わりに適切なテキスト処理ツールを使用してください。:

gawk -F'(,[[:blank:]]+\\[?|\\]\\)\\.)' '!twice{ seen[$2]=NR; next } {
    print $1, "p(" FNR ")", (($3 in seen)?"0, [p("seen[$3]")":"-1, ["$3", "$4)"]).";
}' OFS=', ' infile twice=1 infile

フィールド区切り文字を,<one-or-more-whitespaces><with-optional-]>またはセットとして定義します。]).

入力ファイルをinfile2回処理するので、最初に上記のFSに基づいて2番目のフィールドを読み取り、それを関連する名前付きseen配列に追加します。この配列のキーは2番目のフィールドの内容で、各値はNRです(NRawkで表されます)。窒素数量入力されたレコードFNRは同じですが、次の入力ファイルごとにリセットされます。すべての行を読み取り、完了するまでこのループが繰り返されます。変数twice=1と条件は、!twiceawkが最初のブロックを1回だけ実行し、最初は入力ファイルのみを処理できるようにするために使用されます。

この行はprint2番目の実行のためのもので、最初のフィールドを印刷してp(#)(ここで#sはFNRとして再現されます)、seen配列に一致するものが見つかった場合は、配列内のすべてのキーの3番目のフィールドを確認します。その後、印刷します0, [p(#)]).#配列内の一致するキー値が表示される位置番号はどこにありますか?)。それ以外の場合は印刷します。-1, [...]).

答え2

入力ファイルを「sample.txt」と呼ぶ

まず、ファイルに0と-1ビットを入れる必要があります。

cat sample.txt | sed 's/, \[s/, 0, \[s/g' | sed 's/, \[t/, -1, \[t/g' > sample1.txt

新しい「sample1.txt」ファイルがある場合は、次のbashスクリプト(convert.bash)を実行できます。

#!/bin/bash

k=0
maxstates=$(wc -l "$1" | gawk '{print $1}')

for i in $(seq 1 "$maxstates")
do
    count=$(grep -c "s($i,a)" "$1")
    if [ "$count" -ne 0 ]
    then
        k=$((k + 1))
        sed -i "s/s($i,a)/p($k)/g" "$1"
    fi
    count=$(grep -c "s($i,b)" "$1")
    if [ "$count" -ne 0 ]
    then
        k=$((k + 1))
        sed -i "s/s($i,b)/p($k)/g" "$1"
    fi
done

次に、ファイルを実行します。

bash convert.bash sample1.txt

サンプル1.txtをローカルに編集し、新しいコンテンツは次のとおりです。

state(1, p(1), 0, [p(2)]).
state(1, p(2), 0, [p(1)]).
state(1, p(3), 0, [p(4)]).
state(1, p(4), 0, [p(3)]).
state(1, p(5), 0, [p(6)]).
state(1, p(6), 0, [p(5)]).
state(1, p(7), -1, [t(1), t(2)]).
state(1, p(8), -1, [t(1), t(3)]).
state(1, p(9), 0, [p(10)]).
state(1, p(10), 0, [p(9)]).

関連情報