Нужно заменить слова в тексте пользовательскими синонимами
$string='print the imprint with the imprinted printing paper';
$pattern=array('/print/','/imprint/','/paper/',);
$replacement=array('imprint','print','machine');
Выход:
print the imprint with the imprinted printing machine
Я думаю, что я правильно понимаю, что первые две модели перекрывают друг друга. Я думаю сделать это еще более сложным, но REGEX все еще вуду для меня. С показанной входной строкой я хотел бы получить это обратно: imprint the print with the printed imprinting machine
, Если бы я мог также увидеть, как сделать вывод imprint the print with the imprinted printing machine
Это тоже было бы здорово.
Если бы вы могли объяснить свое регулярное выражение, это было бы более полезно. Может быть, я смогу сделать больше самостоятельно после этого.
2 ответа
Сделайте всю эту замену в одном регулярном выражении, и вы в порядке, потому что за один проход регулярное выражение продолжится после одной замены и не будет пытаться сопоставить замену снова:
$string = 'print the imprint with the imprinted printing paper';
// A single array of find => replace
$replacements = array(
'print' => 'imprint',
'imprint' => 'print',
'paper' => 'machine'
);
// Dynamically form the regex, properly escaping it
$delimiter = '/';
$words = array_keys( $replacements);
$regex = $delimiter . '\b(' . implode('|', array_map( 'preg_quote', $words, array_fill( 0, count( $words), $delimiter))) . ')\b' . $delimiter;
Сформированное регулярное выражение выглядит так:
/\b(print|imprint|paper)\b/
Куда:
\b
это граница слова.()
это группа захвата.print|imprint|paper
является или соответствует одному из этих слов
Наконец, сделать замену:
$result = preg_replace_callback( $regex, function( $match) use( $replacements) {
return $replacements[$match[1]];
}, $string);
echo $result;
Это выведет:
imprint the print with the printed imprinting machine
Если вам нужно выполнить простую замену строки, которая не повторяет строку результата несколько раз, вы должны использовать strtr()
вместо:
strtr($string, array(
'imprint' => 'print',
'print' => 'imprint',
'paper' => 'machine',
));
Слова, которые нужно заменить, упорядочены по длине строки, прежде всего, самой конкретной.
Примечание: это, конечно, не так гибко, как регулярные выражения, особенно когда речь идет о замене только полных слов, т.е. /\bword\b/
будет соответствовать word
только если он стоит сам по себе; это не то, что вы можете сделать с strtr()
и друзья.
Использование регулярных выражений
Делать preg_replace()
выполнить только один проход по строке, вам нужно объединить ключи замены в одно выражение, т.е.
/imprint|print|paper/
Это выражение использует чередование, вызванное символом канала между строками поиска. Чтобы соответствовать только целым словам, вам нужно будет добавить границы соответствия, специальный \b
последовательность, которая соответствует переходу между словами и не словами.
/\b(?:imprint|print|paper)\b/
Это будет соответствовать "imprint"
но нет "pimprint"
,
Если вы идете по этому маршруту, выполнение замены должно быть сделано с помощью preg_replace_callback()
; для каждого совпадения обнаруживается, что выполняется пользовательская функция, в которой вы можете определить, чем ее заменить. Вам нужно будет создать для него карту замены, очень похожую на ту, которую я использовал для моей ранее strtr()
пример.
$map = array(
'imprint' => 'print',
'print' => 'imprint',
'paper' => 'machine',
);
$replacer = function($match) use ($map) {
// $match[0] holds the found word
return $map[$match[0]];
};
preg_replace_callback('/\b(?:imprint|print|paper)\b/', $string, $replacer);
Делать это динамичным
Я создал регулярное выражение вручную, но чтобы сделать его более гибким, вам нужно генерировать его динамически на основе карты замещения. Для этого нам необходимо:
- Извлеките ключи из карты замены;
- Избегайте любых специальных символов;
- Постройте окончательное выражение.
Вот как вы бы построили выражение:
// step 1
$replacement_keys = array_keys($map);
// step 2
$escaped_keys = array_map(function($key) {
return preg_quote($key, '/');
}, $replacement_keys);
// step 3
$pattern = '/\b(?:' . join('|', $escaped_keys) . ')\b/';