用PHP中这样命名的变量替换括号内的文本

时间:2012-08-07 10:23:58

标签: php regex string replace

我想用一个名为该字符串的数组中随机选择的项替换方括号([])中的所有字符串。

它与this issue非常相似,但有一点麻烦,因为我想用名为的数组中的字符串替换不同的括号内容。

一个例子应该让这一点更清晰。

所以说我有字符串

"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。现在,如果通过随机选择它最终重复选择并不重要,但它必须为每个[]项目做出新的选择。

我希望我已经清楚地解释了这一点。如果你得到了我想要达到的目标,并想到一个更好的方法,我会非常感激。

5 个答案:

答案 0 :(得分:8)

算法

  1. 匹配此正则表达式:(\[.*?\])
  2. 对于每个匹配组,从相关数组中选择一个项目。
  3. 按顺序替换字符串。
  4. 实施

    $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:global $adjective = ...。也就是说,我们必须做以下其中一项:

        a)将数组定义为global

          ...
          global $adjective = array("big","small","good","bad");
          global $noun      = array("house","dog","car");
          ...
          function($matches) {
          ...
        

        b)使用use

          ...
          $adjective = array("big","small","good","bad");
          $noun      = array("house","dog","car");
          ...
          function($matches) use ($adjective, $noun) {
          ...
        
      • 回调函数的第一行:

        • 修剪:使用[]功能从匹配中移除方括号(trim)。

        • $ {} :创建一个变量,用作匹配名称的数组名称。例如,如果$match[noun],则trim($matches[1],"[]")返回noun(不带括号),${noun}成为数组名称:$noun。有关该主题的更多信息,请参阅 variable variables

      • 第二行随机选择$array可用的索引号,然后返回此位置的元素。

    • 第三个参数是输入字符串。

答案 1 :(得分:1)

以下代码将完成工作:

$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]部分进行正则表达式匹配,然后使用preg_replace_callback()调用replace_word()回调函数。此函数内部定义了一个内部$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];

这将从replace数组返回$random个元素。在代码片段中,这两行被放在一行中。

仅显示一个元素

如果你想要分离元素(没有两个形容词或名词重复两次),那么你需要做另一个技巧。我们将$replaces数组设置为不在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。以下字符串不起作用:

$string = "This is a very [adjective] [noun], and this is a [adjective] [noun]. This is also an [adjective] [noun] with an [adjective] [noun].";

其中一个输出如下所示,表明我们已经用完了可能的替换:

  

这是一个非常大的房子,这是一个大房子。这也是一个很小的。

答案 2 :(得分:1)

这样做的另一个好(更容易)的方法(不是我的解决方案)

https://stackoverflow.com/a/15773754/2183699

使用foreach检查要替换的变量并用

替换它们
str_replace();

答案 3 :(得分:0)

您可以使用preg_match和str_replace函数来实现此目标。

  • 首先使用preg_match函数查找匹配项,然后创建搜索&从结果中替换数组。
  • 通过将先前的数组作为参数传递来调用str_replace函数。

答案 4 :(得分:0)

这是我对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;