後読みは固定長でなければならないため、この問題を攻撃する方法は機能しません。
IMHOあなたはやりすぎようとしてpreg_relace_callback
います。特定のレベルを超えて複雑な操作を実行したい場合は、単一の関数呼び出しの利便性を犠牲にするのが合理的です。問題を攻撃する別の方法を次に示します。
- 各単語が元のテキストのどこに表示されるかがわかるよう
preg_split
に、フラグとともにテキストを単語に分割するために使用します。PREG_SPLIT_OFFSET_CAPTURE
- 単語の配列を反復処理します。配列に対して「否定後読み」を実行して、帽子やシャツの前に興味のある他の用語のいずれかがあるかどうかを確認するのが非常に簡単になりました。
- 帽子やシャツの正の一致が見つかった場合は常に、正の一致のオフセット
preg_split
と (既知の) 長さを使用substr_replace
して、元のテキスト入力をオンにします。
例えば:
$str = "men's black hat, and orange shirt!";
$targets = array('hat', 'shirt');
$shield = 'men\'s';
$bias = 0;
for ($i = 0; $i < count($words); ++$i) {
list ($word, $offset) = $words[$i];
if (!in_array($word, $targets)) {
continue;
}
for ($j = max($i - 2, 0); $j < $i; ++$j) {
if ($words[$j][0] === $shield) {
continue 2;
}
}
$replacement = 'FOO';
$str = substr_replace($str, $replacement, $offset + $bias, strlen($word));
$bias += strlen($replacement) - strlen($word);
}
echo $str;
実際に見てください。