Я хочу заменить все строки в квадратных скобках ( []
) случайным образом выбранным элементом из массива, названного этой строкой.
Это очень похоже на эту проблему , но с изюминкой, в которой я хочу заменить содержимое различных скобок строками из массивов, названных так.
Пример должен сделать это немного яснее.
Так сказать, у меня есть строка
"This is a very [adjective] [noun], and this is a [adjective] [noun]."
И переменные:
$adjective = array("big","small","good","bad"); $noun = array("house","dog","car");
И мы хотим, чтобы он вернулся: "This is a very big house, and this is a good dog."
или что угодно, путем выбора случайным образом. То есть, я хочу написать функцию PHP, которая заменит каждую [string]
на случайно выбранный элемент из массива с именем $string
. На данный момент не имеет значения, случайно ли он выбирает его, повторяя выбор, но он должен сделать новый выбор для каждого пункта []
.
Надеюсь, я ясно это объяснил. Если вы получите то, что я пытаюсь достичь, и я могу подумать о том, как это сделать, я был бы очень благодарен.
(\[.*?\])
$string = "This is a very [adjective] [noun], and this is a [adjective] [noun]."; $adjective = array("big","small","good","bad"); $noun = array("house","dog","car"); // find matches against the regex and replaces them the callback function. $result = preg_replace_callback( // Matches parts to be replaced: '[adjective]', '[noun]' '/(\[.*?\])/', // Callback function. Use 'use()' or define arrays as 'global' function($matches) use ($adjective, $noun) { // Remove square brackets from the match // then use it as variable name $array = ${trim($matches[1],"[]")}; // Pick an item from the related array whichever. return $array[array_rand($array)]; }, // Input string to search in. $string ); print $result;
Функция preg_replace_callback выполняет поиск и замену регулярных выражений с использованием предоставленной функции обратного вызова.
Первый параметр – это регулярное выражение для соответствия (заключено между /(\[.*?\])/
): /(\[.*?\])/
Второй параметр – это функция обратного вызова для вызова для каждого совпадения. Принимает текущее совпадение в качестве параметра.
Мы должны использовать use()
здесь для доступа к массивам изнутри функции или определения массивов как глобальных: global $adjective = ...
А именно, мы должны сделать одно из следующих действий:
a) Определите массивы как global
:
... global $ adjective = array ("большой", "маленький", "хороший", "плохой"); global $ noun = array («дом», «собака», «автомобиль»); ... функция ($ matches) { ...
b) Использовать:
... $ adjective = array («большой», «маленький», «хороший», «плохой»); $ noun = массив («дом», «собака», «автомобиль»); ... function ($ matches) use ($ adjective, $ noun) { ...
Первая строка функции обратного вызова:
trim : Удаляет квадратные скобки ( []
) из сочетания с использованием функции trim
.
$ {} : Создает переменную для использования в качестве имени массива с именем соответствия. Например, если $match
является [noun]
то trim($matches[1],"[]")
возвращает noun
(без скобок), а ${noun}
становится именем массива: $noun
. Дополнительные сведения о теме см. В переменных переменных .
Вторая строка случайным образом выбирает номер индекса, доступный для $array
и затем возвращает элемент в этой позиции.
Третий параметр – входная строка.
Следующий код будет выполнять следующие действия:
$string = "This is a very [adjective] [noun], and this is a [adjective] [noun]." function replace_word ( $matches ) { $replaces = array( '[adjective]' => array("big", "small", "good", "bad"), '[noun]' => array("house", "dog", "car") ); return $replaces[$matches[0]][array_rand($replaces[ $matches[0] ])]; } echo preg_replace_callback("(\[.*?\])", "replace_word", $string);
Во-первых, мы сопоставляем регулярное выражение по [something]
части [something]
части слова и вызываем replace_word()
обратного вызова replace_word()
на нем с помощью preg_replace_callback()
. Эта функция имеет внутренний $replaces
два массива глубины измерения, определенные внутри, каждая строка определена в [word type] => array('rep1', 'rep2', ...)
.
Сложная и немного запутанная строка – это return $replaces[$matches[0]][array_rand($replaces[ $matches[0] ])];
, Если я немного его сломаю, это будет намного более понятным для вас:
$random = array_rand( $replaces[ $matches[0] ] );
$matches[0]
– это тип слова, это ключ в массиве $replaces
мы ищем. Это было найдено путем регулярного выражения в исходной строке. array_rand()
основном выбирает один элемент массива и возвращает его числовой индекс . Таким образом, $random
прямо сейчас представляет собой целое число где-то между 0
и (number of elements - 1)
массива, содержащего замены.
return $replaces[ $matches[0] ][$random];
Это вернет $random
элемент $random
из массива replace. В фрагменте кода эти две строки объединены в одну строку.
Если вам нужны дизъюнктные элементы (два прилагательных или существительное повторяются дважды), вам нужно будет сделать еще один трюк. Мы установим массив $replaces
replace_word()
должен быть определен не внутри функции replace_word()
, а вне его.
$GLOBALS['replaces'] = array( '[adjective]' => array("big", "small", "good", "bad"), '[noun]' => array("house", "dog", "car") );
Внутри функции мы будем устанавливать локальную переменную $replaces
ссылку на вновь заданный массив, с вызовом $replaces = &$GLOBALS['replaces'];
, (Оператор &
присваивает ему ссылку , поэтому все, что мы делаем с помощью $replaces
(например, удаление и добавление элементов), также изменяет исходный массив. Без него это будет только копия.)
И перед тем, как прибыть на return
линию, мы вызываем unset()
в текущем возвращаемом ключе.
unset($replaces[$matches[0]][array_rand($replaces[ $matches[0] ])]);
Теперь эта функция выглядит следующим образом:
function replace_word ( $matches ) { $replaces = &$GLOBALS['replaces']; unset($replaces[$matches[0]][array_rand($replaces[ $matches[0] ])]); return $replaces[$matches[0]][array_rand($replaces[ $matches[0] ])]; }
И поскольку $replaces
ссылку на глобальную, unset()
обновляет исходный массив. Следующий вызов replace_word()
не найдет ту же замену снова.
Строки, содержащие больше заменяющих переменных, чем количество заменяемых значений, будут E_NOTICE
неопределенный индекс E_NOTICE
. Следующая строка не будет работать:
$string = "This is a very [adjective] [noun], and this is a [adjective] [noun]. This is also an [adjective] [noun] with an [adjective] [noun].";
Один из выходов выглядит следующим образом, показывая, что у нас закончились возможные замены:
Это очень большой дом, и это большой дом. Это также маленький с.
Еще один хороший (более простой) способ сделать это (не мое решение)
https://stackoverflow.com/a/15773754/2183699
Использование foreach для проверки того, какие переменные вы хотите заменить и заменить их
str_replace();
Вы можете использовать функцию preg_match и str_replace для достижения этой цели.
Это мое небольшое обновление для ответа mmdemirbas выше. Он позволяет вам устанавливать переменные вне функции (т. Е. Использовать глобальные переменные, как сказано).
$result = preg_replace_callback( // Matches parts to be replaced: '[adjective]', '[noun]' '/(\[.*?\])/', // Callback function. Use 'use()' or define arrays as 'global' function($matches) use ($adjective, $noun) { // Remove square brackets from the match // then use it as variable name $arrayname = trim($matches[1],"[]"); $array = $GLOBALS[$arrayname]; // Pick an item from the related array whichever. return $array[array_rand($array)]; }, // Input string to search in. $string ); print $result;