Заменить текст в скобках так называемой переменной в PHP

Я хочу заменить все строки в квадратных скобках ( [] ) случайным образом выбранным элементом из массива, названного этой строкой.

Это очень похоже на эту проблему , но с изюминкой, в которой я хочу заменить содержимое различных скобок строками из массивов, названных так.

Пример должен сделать это немного яснее.

Так сказать, у меня есть строка

 "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 . На данный момент не имеет значения, случайно ли он выбирает его, повторяя выбор, но он должен сделать новый выбор для каждого пункта [] .

Надеюсь, я ясно это объяснил. Если вы получите то, что я пытаюсь достичь, и я могу подумать о том, как это сделать, я был бы очень благодарен.

Алгоритм

  1. Соответствие для этого регулярного выражения: (\[.*?\])
  2. Для каждой группы соответствия выберите элемент из связанного массива.
  3. Замените строку по порядку.

Реализация

 $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 для достижения этой цели.

  • Сначала найдите совпадения, используя функцию 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;