1

まず、正規表現は xml の解析には適していないことを理解しています。代わりに xml パーサーを使用する必要があります。おそらく、私の質問は、これが真実である理由の良い例です。

そうは言っても、私がする必要があるのは、いくつかの XML ファイルを 1 回だけ検索して置換することだけです。さらに、私は正規表現に比較的慣れていないので、正規表現をよりよく理解し、XMLにとってなぜそれが悪い考えなのかを理解したいと思っています。

次の XML があります (元のファイルにはタグ間にスペースがありません!):

<tag1>
    <tag2>Doesn't matter what is here</tag2>
</tag1>
<tag1>
    <tag2>Anything can <b>go<b> here</tag2>
    <tag3>Hi there</tag3>
</tag1>

tag3 内の「こんにちは」を 2 つの部分に分割する必要があります。これらは両方とも tag1 に囲まれ、存在する場合は同じ tag2 を持ちます。つまり、次のようになります。

<tag1>
    <tag2>Doesn't matter what is here</tag2>
</tag1>
<tag1>
    <tag2>Anything can <b>go<b> here</tag2>
    <tag3>Hi</tag3>
</tag1>
<tag1>
    <tag2>Anything can <b>go<b> here</tag2>
    <tag3>there</tag3>
</tag1>

私の最初のアイデアは、次のように貪欲でない量指定子を持つ tag2 のオプションのグループを使用することでした:

<tag1>(<tag2>.*?</tag2>)?<tag3>Hi there</tag3></tag1>

(Java 構文) に置き換えます。

<tag1>$1<tag3>Hi</tag3></tag1><tag1>$1<tag3>there</tag3></tag1>

しかし 。*?まだ貪欲すぎます。tag1 の最初の開始から tag1 の最後の終了まで一致します。これを行う適切な正規表現の方法は何ですか? それとも、これは正規表現にとって難しい問題ですか? これが、XML に正規表現を使用することが非常に悪い考えである理由の 1 つですか?

アトミックグループを使用すると、まさに私が望むことができることがわかりました。

<tag1>(?>(<tag2>.*?</tag2>))?<tag3>Hi there</tag3></tag1>

しかし、なぜそうなのかはよくわかりません。なぜこれが機能し、これは十分に信頼できるのでしょうか?

4

1 に答える 1

1

OK、正規表現の動作について説明します。

1. 最初の正規表現のマッチング動作

<tag1>(<tag2>.*?</tag2>)?<tag3>Hi there</tag3></tag1>

パターンは で一致を開始し<tag1><tag2>this も一致し、.*?最初の まで一致し</tag2>ます。結構ですが、パターンには a<tag3>に従う必要があり、ないため、正規表現はバックトラックして最初の を と一致</tag2>させ.*?、次に.*?は次の まですべてに一致させ</tag2>ます。そこに次のものが見つかり、<tag3>正常に終了できます。

2. アトミック グループ バージョンのマッチング動作

<tag1>(?>(<tag2>.*?</tag2>))?<tag3>Hi there</tag3></tag1>

パターンは で一致を開始し<tag1><tag2>this も一致し、.*?最初の まで一致し</tag2>ます。

この時点まで、動作は最初の正規表現とまったく同じです。

しかし、現在は<tag3>フォローがありませんが、atomic グループがバックトラッキングを防止しているため、正規表現は失敗します。

成功した瞬間から再開し<tag1>ます。

于 2012-10-23T10:07:57.870 に答える