3

名前空間のクラス名を置き換えることを意図した正規表現から予期しない結果が得られます。置換が 2 回行われたように見えるため、置換されるクラス名が重複しています (以下の例を参照)。

+実際には、正規表現を0以上 ( ) ではなく 1 以上 ( ) に一致するように変更することで問題を解決しました*。これは、実際には必要なものに対してより正確です。

しかし、そもそもなぜ問題が発生したのか、少し混乱しています。

問題の例を次に示します。

$classns  = 'components\groups\GroupsController';
$newclass = 'GroupsAccess';
$classns = preg_replace('/[^\\\\]*$/', $newclass, $classns);
echo $classns;

結果

components\groups\GroupsAccessGroupsAccess

期待される

components\groups\GroupsAccess

* が単語境界またはその性質のものと一致している可能性はありますか?

私にとって紛らわしい部分は、同じ正規表現を使用した preg_match が 1 つの結果しか表示しないため、preg_match が正規表現を実行する方法に固有のもののように見えることです。

例えば

preg_match('/[^\\\\]*$/', $classns, $m);
var_dump($m);

結果

array(1) { [0]=> string(12) "GroupsAccess" }
4

2 に答える 2

5

*単語境界に一致していません。空の文字列に一致しています。

あなたの表現は最初に一致します

components\groups\ GroupsController

the$は位置に一致し、文字列\nの末尾の前 (または文字列の末尾の a) にあるアンカーです。

したがって、最初の一致の後、正規表現パーサーの位置は、最後の「r」の後、文字列の末尾の前になり、正規表現を再度一致させようとします。そして、もう 1 つの一致 ==> 0 回の/(空の文字列) の後に文字列の末尾が続きます。

次に進み、文字列の終わりを認識して終了します。

于 2012-12-04T14:45:10.087 に答える
2

絞り込むと、これも 2 つの一致が表示されます。

preg_match_all('/a*$/', 'a', $m);`

Python の動作は同じです。

>>> re.findall('a*$', 'a')
['a', '']

Perlもそうです:

>>> my @m = 'a' =~ /a*$/g;
>>> foreach (@m) { print "$_\n"; }
a
<blank>

'a'正規表現エンジンは、 とそれに続く空の文字列の両方に一致''するようです。技術的にはこれは正しいですが、驚くべきことです。'a'は検索文字列の末尾に固定されている文字列であり、''.

一致の基本ルールの 1 つは、一致が重複しないことです。一致が見つかると、正規表現エンジンは前の一致の終わりに次の一致を検索し続けます。私が予想していなかったのは$、おそらくアンカーがゼロ幅のアサーションであり、実際の部分文字列の一致ではないため、アンカーを再利用できることです。

于 2012-12-04T14:55:57.250 に答える