1

(おそらく複雑な) RegExp の質問があります。モデルからファイルを生成するツールで、モデルが名前を 2 回使用していると表示されますが、これがどの名前であるかは表示されません。問題の名前はすべて「CK_」で始まり、その後に空白以外が続くことを知っています。このテストファイルを準備しました:

CK_123abc
foo
CK_abc
CK_123abc
CK_199
bar
CK_177
bar
CK_188

ご覧のとおり、「CK_123abc」が 2 回表示されています。RegExp を使用して、それらすべて (さらにある場合) をキャッチしたいと考えています。これまでに取得したもの: (CK_\S*).+\1

これは正常に機能し、次のテキストと一致します。

CK_123abc
foo
CK_abc
CK_123abc

しかし、それも一致します

CK_199
bar
CK_177
bar
CK_1

2 番目の不要な一致はCK_1です。私の実際のドキュメントはこれらの「半文字列」一致でいっぱいであるため、データ内で実際の一致 (ここの最初のものなど) を見つけることができません。(CK_\S*)は何らかの理由で貪欲ではない、または正規表現全体が貪欲であると思います。私のユースケースが機能するには、(CK_\S*)が最初に可能な限り一致する必要があり、その後、ドキュメントの後半で同じ一致が見つかるはずです。

私はメモ帳++を使用しています(PCREを使用)。「。」"\r"および"\n"に一致します。

どんな指針も高く評価されます。

4

4 に答える 4

2

問題は量指定子の貪欲さや怠惰さではなく、正規表現エンジンの動作方法です。正規表現エンジンは、パターンが失敗した場合、バックトラッキング メカニズムを使用して(パターンが成功するまで、または可能性がなくなるまで)他の可能性を試す可能性があり、文字列内の同じ位置からそれを行います。

この動作を緩和する唯一の方法は、ここのいくつかの回答でわかるように、パターンに制約を追加することです(可能性を制限するため) 。

アイデアは、後方参照に対して同じことを忘れずに、スペース、単語境界、または所有量指定子を使用して名前の制限(左右)をチェックすることです。

スペースあり: (?:\s|^)(CK_\S*)(?=\s.*(?<=\s)\1(?:\s|$)) (少し長いですが、おそらく最も防水性の高い方法です)

単語境界あり:\b(CK_\S*)\b(?=.*\b\1\b)

所有量指定子と単語境界を使用:\b(CK_\S*+)(?=.*\b\1\b)

注: ドットが使用されているため、すべてのパターンでシングルライン モードをオンにする必要があります。

于 2014-07-02T23:33:41.080 に答える