Я хочу заменить все строки в квадратных скобках ( [] ) случайным образом выбранным элементом из массива, названного этой строкой.
Это очень похоже на эту проблему , но с изюминкой, в которой я хочу заменить содержимое различных скобок строками из массивов, названных так.
Пример должен сделать это немного яснее.
Так сказать, у меня есть строка
"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;