1

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

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

一个例子应该使这更清楚一点。

所以说我有字符串

"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. 目前,随机选择是否会导致重复选择并不重要,但它必须为每个[]项目做出新的选择。

我希望我已经清楚地解释了这一点。如果你能得到我想要达到的目标并且能想出更好的方法来做到这一点,我将不胜感激。

4

5 回答 5

8

算法

  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: global $adjective = ...。即,我们必须执行以下操作之一:

      a)将数组定义为global

        ...
        全局 $adjective = array("big","small","good","bad");
        全局 $noun = array("house","dog","car");
        ...
        功能($匹配){
        ...
      

      b)使用use

        ...
        $形容词=数组(“大”,“小”,“好”,“坏”);
        $noun = array("房子","狗","汽车");
        ...
        函数($matches)使用($形容词,$名词){
        ...
      
    • 回调函数的第一行:

      • trim :使用函数[]从匹配中删除方括号 ( )。trim

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

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

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

于 2012-08-07T10:34:16.870 回答
1

这样做的另一种好(更简单)方法(不是我的解决方案)

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

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

str_replace();
于 2014-01-08T16:37:54.180 回答
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]首先,我们对单词的部分进行正则表达式匹配,并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替换数组中的第 th 个元素。在代码片段中,这两行放在一起成为一行。

一个元素只显示一次

如果你想要分离元素(没有两个形容词或名词重复两次),那么你需要做另一个技巧。我们将设置$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].";

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

这是一所非常大的房子,而且这是一所大房子。这也是一个小带。

于 2012-08-07T10:50:55.553 回答
0

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

  • 首先使用 preg_match 函数找到匹配项,然后从结果中创建搜索和替换数组。
  • 通过将先前的数组作为参数传递来调用 str_replace 函数。
于 2012-08-07T10:47:02.670 回答
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;
于 2012-08-11T15:02:04.453 回答