我想将方括号([]
)中的所有字符串替换为从命名为该字符串的数组中随机选择的项。
这与这个问题非常相似,但有一点不同,因为我想用名为它的数组中的字符串替换不同括号的内容。
一个例子应该会让这一点更加清晰
假设我有字符串
"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:global $adjective = ...
。也就是说,我们必须执行以下操作之一:a)将阵列定义为
global
:。。。global$形容词=数组("大"、"小"、"好"、"坏");global$norn=数组("house"、"dog"、"car");。。。函数($matches){。。。
b)使用
use
:。。。$形容词=数组("大"、"小"、"好"、"坏");$norn=数组("房子"、"狗"、"车");。。。函数($matches)用法($形容词,$名词){。。。
回调函数的第一行:
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]
部分进行正则表达式匹配,并用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];
这将返回替换数组中的第33个CCD_元素。在代码片段中,这两行被放在一起成为一行。
只显示一个元素一次
如果你想要析取元素(没有两个形容词或名词重复两次),那么你需要做另一个技巧。我们将把$replaces
数组设置为不在replace_word()
函数内部定义,而是在它外部定义
$GLOBALS['replaces'] = array(
'[adjective]' => array("big", "small", "good", "bad"),
'[noun]' => array("house", "dog", "car")
);
在函数内部,我们将通过调用$replaces = &$GLOBALS['replaces'];
,将本地$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].";
其中一个输出看起来如下,表明我们已经用完了可能的替代品:
这是一栋很大的房子,这是一座很大的房子。这也是一个带有的小。
另一种很好(更容易)的方法(不是我的解决方案)
https://stackoverflow.com/a/15773754/2183699
使用foreach检查要替换的变量,并用替换它们
str_replace();
您可以使用preg_match和str_replace函数来实现此目标。
- 首先使用preg_match函数查找匹配项,然后创建search&从结果中替换数组
- 通过将前面的数组作为参数传递来调用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;