2017-05-12 7 views
4
$str = 'کس نے موسیٰ کے بارے میں سنا ہے؟'; 
$str = preg_replace('/(?<=\b)موسیٰ(?=\b)/u', 'Musa', $str); 
$str = preg_replace('/(?<=\b)سنا(?=\b)/u', 'suna', $str); 
echo $str; 

これは、موسیٰの代わりに失敗します。それはکس نے Musa کے بارے میں suna ہے؟を与えるべきである代わりにکس نے موسیٰ کے بارے میں suna ہے؟を与える。一部の単語/文字でpreg_replaceが機能しない

これは、ٰで終わるすべての単語(تعالیٰなど)で発生しています。 ٰが単語の途中にある単語(単語はٰで始まりません)の場合に機能します。これは\bٰで動作しないことを意味しますか?バグですか?

答えて

1

理由は、単語の境界には、次の位置に一致していることである:最初の文字がある場合、文字列の最初の文字の前に

  • 単語の文字。
  • 文字列の最後の文字の後に、最後の文字が単語文字の場合。
  • 文字列内の2文字の間に、1つは単語文字であり、もう1つは単語文字ではありません。

"問題" 記号は、(マークのUnicodeカテゴリをノンスペーシング)\p{Mn}に属するU+0670ARABIC LETTER SUPERSCRIPT ALEFであるので、非ワードシンボルあります。 \bは、\w(文字、数字、_)に属するcharが前に付いている場合に一致します。

使用明確な境界は、検索語句が先行していない場合にのみ/ワード文字に続く:

$str = 'کس نے موسیٰ کے بارے میں سنا ہے؟'; 
$str = preg_replace('/(?<!\w)موسیٰ(?!\w)/u', 'Musa', $str); 
$str = preg_replace('/(?<!\w)سنا(?!\w)/u', 'suna', $str); 
echo $str; // => کس نے Musa کے بارے میں suna ہے؟ 

PHP demoを参照してください。

(?<!\w)は、負のlookbehindであり、次の消費パターンの直前にwordという文字がないことを確認し、(?!\w)は負の先読みで、前の消費パターンの直後にwordという文字がないことを確認します。

+0

少し説明が修正されています:* '\ b'は、前に**あるならば一致し、**が' \ w' *に属しています(パターンに '\ b'が2つあります)。 –

1

コード:

$ strの= '?کسنےموسیکےبارےمیںسناہے'; $ patterns = ['/موسی/ u'、 '/سنا/ u']; $ replacements = ['Musa'、 'suna']; echo preg_replace($ patterns、$ replacement、$ str);

恐らく、最初のパターンのスペースや開始/終了をチェックすることで、単語の境界を偽ることができますか?

$str = 'کس نے موسیٰ کے بارے میں سنا ہے؟'; 
$patterns[]='/(?<= |^)موسیٰ(?= |$)/u'; 
$patterns[]='/\bسنا\b/u'; 
// or \s perhaps instead of blank space 
$replacements=['Musa','suna']; 
echo preg_replace($patterns,$replacements,$str); 

出力:

کس نے Musa کے بارے میں suna ہے؟ 
+0

@Travis私のパターンは、あなたが別の '$のstr'を使用する場合、私はそれに対してテストすることができますので、その場合を提供してください失敗した場合。さもなければ、このより単純なパターンは私にとって正しいようです。 – mickmackusa

+0

\ bは、他の単語の一部である単語に必要です。 $ str = '彼はこんにちは'; $ patterns = ['/ he/u']; $ replacements = ['/ Tom/u'];あなたの例ではTomがTomlloに言った。 または、 '$ str = 'を試してみてください。'; '。それは正しく動作しません。 – Travis

0

Be careful that

\b\Bは... \w\Wで定義されています。

\w(*UCP)オプションまたは他のすべての言語から他のアルファベットではなく組み合わせたマークを含むように\w変化のuユニコード修飾子の定義を使用しながら、しかし、ASCIIテーブルに該当する単語文字に一致します。

\bは、マークそのものが非単語キャラクタとみなされるため、ٰのようなマークが非単語キャラクタを見る位置には決して一致しません。何をしようとする

は、より多くの任意の非単語文字の前後の単語موسیٰがある場合はそう\Sメタ文字は仕事をしていませんアサート考え出すようなものです:

(?<!\S)موسیٰ(?!\S) 

ように達成する別の方法

<?php 

$strings = [ 
    'is' => 'کس نے موسیٰ کے بارے میں سنا ہے؟', // input string 
    'wts' => 'موسیٰ' // word to search 
]; 

array_walk($strings, function(&$value) { 
    $value = transliterator_transliterate('[:Nonspacing Mark:] Remove;', $value); 
}); 

// word boundaries now can be used 
echo preg_replace('/\b' . $strings['wts'] . '\b/u', 'musa', $strings['is']); 
:タスクは、組み合わせマーク ٰが含まれていない単語 موسیに一致するようにしようと、すべてのアクセントを削除するためにICUライブラリを使用して transliterating全体の入力文字列になりますの

出力:

کس نے musa کے بارے میں سنا ہے؟ 
関連する問題