私はこの文字列を持っています:
update mytable set mycol=myvalue where mycol=yourvalue;
次に変換する必要があります。
insert into mytemp select * from mytable where mycol=youvalue;
私はこれを行うことができ、見事に動作します。
sed -e 's/^Update.*where//ig' -e "s/^/insert into mytemp select * from mytable where /g" n.txt
しかし、:
文字列が次の場合:
update mytable set mycol=myvalue where mycol=(select yourcol from yourtable where youcol=yourvalue);
私は得る:
insert into mytemp select * from mytable where youcol=yourvalue);
そして私はほしい:
insert into mytemp select * from mytable where mycol=(select yourcol from yourtable where youcol=yourvalue);
どうですか?
答え1
基本的に、sed
正規表現エンジンは貪欲です。これは、パターンが常に可能な最長の一致と一致することを意味します。貪欲ではない検索をする必要がありますが、sedは貪欲な検索をサポートしていないようです。したがってsed
、可能な限り短い一致を見つけるために、検索パターンにピボットポイントを追加する必要があります。
次の行は、貪欲ではない特殊なw
マッチングをシミュレートしようとします。update
where
sed -e 's/^Update[^w]*where//ig'\
-e "s/^/insert into mytemp select * from mytable where /g" n.txt
perl
およびいずれかのような他の正規表現エンジンはこの機能をサポートしていますawk
。
しかし、あなたの場合は、次のような表現が必要だと思います。
sed -e 's/^Update.\+where\(.\+where.*\)$/\
insert into mytemp select * from mytable where \1/ig' n.txt
あなたの特定の質問にもっと便利になります。
(上記のラインの予告編は、\
ラインをより明確にするために追加されました。)
答え2
正規表現の一致は左から右に進み、最も長い一致に優先順位を付けます。したがって、その行^Update.*where
の最後の項目と一致します。where
このマッチングを実行する1つの方法は、non-greedy数量子を使用することです*
。 Sedは非greedy数量子をサポートしていませんが、Perlはサポートしています。
perl -pe 's/^update.*?where//i; s/^/insert into mytemp select .*? from mytable where /'
データと一致する場合と一致しない可能性がある別のアプローチは、テーブル名と列設定で括弧を拒否することです。
sed -e 's/^update[^()]*where//i' -e 's/^/insert into mytemp select [^()]* from mytable where /'
より洗練されたアプローチは、最初のwhere
最初のトークンを一意のトークンに置き換えてから置換を実行し、最後にトークンをに復元することですwhere
。 sed は 1 行ずつ実行されるため、\n
次のように行に改行文字が含まれないことが保証されます。 sed。
sed -e 's/ where /\n/' \
-e 's/^update.*$//i' -e 's/^/insert into mytemp select .* from mytable where /' \
-e 's/\n/ where/'