我认为仅限于使用str_replace时的主要问题是您几乎无法控制哪些字符串被替换(因为所有事件都会被替换),并且在选择占位符时需要特别小心对于\@转义序列。两个插入的值组合可能会生成占位符字符串,因此在还原占位符替换时将其转换为@字符。
以下是一种蛮力的解决方案,试图解决这个问题。它一次检查一个占位符对照模板字符串,替换值和最终字符串,确保占位符不出现在任何这些字符串中,并且最初为\@引入的占位符数与该数字匹配占位符还原。您可能希望设置一个默认的占位符,而不是xyz(如零char或其他),最适合您,以避免不必要的处理。
可以使用两种替换模式(@和@)调用它,但目前它们不能混合使用。
这不是我写过的最漂亮的代码,但鉴于str_replace约束,它仍然是我的镜头,我希望它对你有所帮助。
function templateMap ($string, $array, $defaultPlaceholder = "xyz")
{
$newArray = array();
// Create an array of the subject string and replacement arrays
$knownStrings = array($string);
foreach ($array as $subArray) {
if (is_array($subArray)) {
$knownStrings = array_merge($knownStrings, array_values($subArray));
}
else {
$knownStrings[] = $subArray;
}
}
$placeHolder = '';
while (true) {
if (!$placeHolder) {
// This is the first try, so let's try the default placeholder
$placeHolder = $defaultPlaceholder;
}
else {
// We've been here before - we need to try another placeholder
$placeHolder = uniqid('bs-placeholder-', true);
}
// Try to find a placeholder that does not appear in any of the strings
foreach ($knownStrings as $knownString) {
// Does $placeHolder exist in $knownString?
str_replace($placeHolder, 'whatever', $knownString, $count);
if ($count > 0) {
// Placeholder candidate was found in one of the strings
continue 2; // Start over
}
}
// Will go for placeholder "$placeHolder"
foreach ($array as $subArray) {
$newString = $string;
// Apply placeholder for \@ - remember number of replacements
$newString = str_replace(
'\@', $placeHolder, $newString, $numberOfFirstReplacements
);
if (is_array($subArray)) {
// Make substitution on @
for ($i = 0; $i <= 9; $i++) {
@$newString = str_replace("@$i", $subArray[$i], $newString);
}
}
else {
// Make substitution on @
@$newString = str_replace("@", $subArray, $newString);
}
// Revert placeholder for \@ - remember number of replacements
$newString = str_replace(
$placeHolder, '@', $newString, $numberOfSecondReplacements
);
if ($numberOfFirstReplacements != $numberOfSecondReplacements) {
// Darn - value substitution caused used placeholder to appear,
// ruining our day - we need some other placeholder
$newArray = array();
continue 2;
}
// Looks promising
$newArray[] = $newString;
}
// All is well that ends well
break;
}
return $newArray;
}
$a = templateMap(
"(@ and one escaped \@)",
array(" col1 < 5 && col2 > 6", " col3 < 3 || col4 > 7")
);
print_r($a);
$a = templateMap(
"You can tweet @0 \@2 @1",
array(
array("Sarah", "ssarahtweetz"),
array("John", "jjohnsthetweetiest"),
)
);
print_r($a);
输出:
Array
(
[0] => ( col1 < 5 && col2 > 6 and one escaped @)
[1] => ( col3 < 3 || col4 > 7 and one escaped @)
)
Array
(
[0] => You can tweet Sarah @2 ssarahtweetz
[1] => You can tweet John @2 jjohnsthetweetiest
)