1. ホーム
  2. php

[解決済み] preg_replace() の e 修飾子を preg_replace_callback に置き換える。

2023-05-17 04:04:14

質問

私は正規表現が苦手です。これを置き換えようとしています。

public static function camelize($word) {
   return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}

のように、preg_replace_callbackを無名関数に置き換えています。この関数が何をやっているのか分からない。というか、preg_replace_callbackがどのように動作するのか正確に理解していない。

これを達成するための正しいコードは何でしょうか?

どのように解決するのですか?

正規表現では、マッチした文字列の一部を、"capt". (brackets) で囲むことができます。 (^|_)([a-z]) の部分があります。これらには1から始まる番号が振られているので、後方参照1と2があることになります。マッチ0はマッチした文字列全体です。

/e 修飾子は置換文字列を受け取り、バックスラッシュの後に数字を付けて置換します (例. \1 ) を適切な後方参照に置き換えます。 しかし、文字列の中にいるので、バックスラッシュをエスケープする必要があり、 その結果 '\\1' . そして、(事実上)次のように実行されます。 eval を実行して、結果の文字列をあたかも PHP のコードのように実行します (これが非推奨とされている理由です。 eval を安全でない方法で使うことが簡単にできるからです)。

preg_replace_callback 関数は代わりにコールバック関数を受け取り、マッチした後方参照を含む配列を渡します。ですから、あなたが '\\1' と書くところを、代わりにそのパラメータの要素 1 にアクセスすることになります。 function($matches) { ... } という形の無名関数があった場合、最初の後方参照は $matches[1] で、その関数の内部です。

ということは /e の引数は

'do_stuff(\\1) . "and" . do_stuff(\\2)'

のコールバックとなる可能性があります。

function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }

あるいは、あなたの場合

'strtoupper("\\2")'

になる可能性がある。

function($m) { return strtoupper($m[2]); }

なお $m$matches はマジックネームではなく、コールバック関数を宣言するときにつけたパラメータ名です。また、無名関数を渡す必要はなく、関数名を文字列として渡すこともできますし、次のような形式のものでもよいでしょう。 array($object, $method) , PHP の他のコールバックと同様に のように、例えば

function stuffy_callback($things) {
    return do_stuff($things[1]) . "and" . do_stuff($things[2]);
}
$foo = preg_replace_callback('/([a-z]+) and ([a-z]+)/', 'stuffy_callback', 'fish and chips');

他の関数と同様に、デフォルトではコールバックの外(周囲のスコープから)の変数にアクセスすることはできません。無名関数を使用する場合は、コールバック内の変数にアクセスするために use キーワードを使用して、アクセスする必要のある変数をインポートすることができます。 PHP のマニュアルで説明されているように ...例えば、古い引数が

'do_stuff(\\1, $foo)'

とすると、新しいコールバックは次のようになります。

function($m) use ($foo) { return do_stuff($m[1], $foo); }

注意事項

  • 使用方法 preg_replace_callback の代わりに /e という修飾子がつくので、そのフラグを "pattern" 引数から削除する必要があります。そのため、次のようなパターンが /blah(.*)blah/mei は次のようになります。 /blah(.*)blah/mi .
  • /e モディファイアは addslashes() を使うので、いくつかの置き換えでは、引数で stripslashes() を使って削除することもできます。 stripslashes への呼び出しを削除したいでしょう。