下面的代码将完成这项工作:
$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].";
其中一个输出如下所示,表明我们用完了可能的替换:
这是一所非常大的房子,而且这是一所大房子。这也是一个小带。