2

私の目標は、末尾のすべてのインスタンスをタグブラケット内の末尾の+に置き換えることです。置き換えられる行が次のようになっていると仮定します。

<h> aa- aa- </h> <h> ba- ba- </h> 

その後は次のようになります

<h> aa+ aa+ </h> <h> ba+ ba+ </h>

最初に私はこの表現を試しました:

s/<h>(.*?)-(.*?)<\/h>/<h>$1+$2<\/h>/g;

これにより、次の出力が得られました。

<h> aa+ aa- </h> <h> ba+ ba- </h>

gオプションを使用すると、行ごとに複数の置換が行われますが、タグブラケットごとの最初のインスタンスに対してのみです(両方の丸括弧に疑問符が含まれている場合のみ)。

問題を絞り込むために、タグを無視して置換を実現しようとしました。表現

s/(.*?)-(.*?)/$1+$2/g; 

確かに望ましい結果につながります

<h> aa+ aa+ </h> <h> ba+ ba+ </h>

もちろん、これはタグブラケットの外側でも置き換えられます。

では、最初の式の問題は何ですか。また、タグ括弧内で完全に置換するという目標をどのように達成できますか?

4

2 に答える 2

1

正規表現を使用して XML を解析しているため (一般的には良い考えではありません)、入力についていくつかの仮定を立てても構わないと思っていると思います。もしそうなら、次の置換で十分かもしれません。

マイナス記号が次の場合、マイナス記号をプラス記号に置き換えます: (a) 単語の境界で、(b) 任意の非左角括弧テキストと終了タグが続きます。有効なドキュメントを想定できる場合は、開始タグについて心配する必要はありません。2 番目の条件は、正規表現が文字列を消費しないように先読みアサーションで適用され、そのようなマイナス記号をすべて置き換えることができます。

s/ \b- (?= [^<]* <\/h>) /+/xg;

もう 1 つのオプションは、何も置き換えられなくなるまで正規表現を実行することです。スカラー コンテキストでは、グローバル置換は行われた置換の数を返します。これは、行の処理をいつ停止するかのテストとして役立ちます。

my $n = 1;
$n = s/YOUR_REGEX/YOUR_REPLACE/g while $n;
于 2010-08-01T13:17:14.867 に答える
0

これを行う 1 つの方法を次に示します。文字列をタグ付きビットとタグなしビットに分割し、タグ付きビットに対してのみ置換を実行します。

$_ = join("", map { if(/^<h>/) { # if it's a tagged bit...
                        s/-($|\s|<)/+$1/g; # replace all trailing '-'s
                    }
                    $_}
                  split m!(<h>.*?</h>)!) # split into tagged and non-tagged bits
于 2010-08-01T12:13:00.910 に答える