用分组单词数组中的随机单词替换字符串中的整个单词
Replace whole words in a string with a random word from an array of grouped words
$myVar = 'essa pizza é muito gostosa';
$myWords=array(
array('sabor','gosto','delicia'),
array('saborosa','gostosa','deliciosa'),
);
foreach($myWords as $words){
// randomize the subarray
shuffle($words);
// pipe-together the words and return just one match
if(preg_match('/\b\K'.implode('|',$words).'\b/',$myVar,$out)){
// generate "replace_pair" from matched word and a random remaining subarray word
// replace and preserve the new sentence
$myVar=strtr($myVar,[$out[0]=>current(array_diff($words,$out))]);
}
}
echo $myVar;
应替换为:
$myVar = 'essa pizza é muito deliciosa';
或
$myVar = 'essa pizza é muito saborosa';
但是您正在换取较小的单词键,只是因为这个较小的键也包含这个较大键的所有字母!
正在发生的输出是错误的:
$myVar = 'essa pizza é muito saborsa';
"saborsa"(这个词在葡萄牙语和我的数组中都不存在)!
正在切字"gostosa",放字"sabor"
然后,不是输入单词 "saborosa," 而是形成不存在的单词:"saborsa"。 word "gostosa" = "sa" + word "sabor" = "saborsa" 的一部分(这个词不存在)必须是 "saborosa".
最大的问题是将单词 "gostosa" 的一部分视为单词 "gosto"
如何在替换之前阅读完整的关键字/单词?
谢谢
多年后我才看到我原来的答案,并意识到它不是为了进行多次随机替换而构建的。我删除了旧答案,用更可靠的技术取而代之。
代码:(Demo)
$myVar = 'essa pizza é muito gostosa, gostosa, gostosa, gosto';
$myWords = [
['sabor', 'gosto', 'delicia'],
['saborosa', 'gostosa', 'deliciosa'],
];
$grouped = [];
$flipped = [];
foreach ($myWords as $row) {
$grouped[] = '(' . implode('|', $row) . ')';
$flipped[] = array_flip($row);
}
$pattern = '/\b(?:' . implode('|', $grouped) . ')\b/';
var_export(
preg_replace_callback(
$pattern,
function($m) use ($flipped) {
array_shift($m);
foreach ($m as $i => $captured) {
if ($captured) {
unset($flipped[$i][$captured]);
return array_rand($flipped[$i]);
}
}
},
$myVar
)
);
潜在产出:
'essa pizza é muito deliciosa, saborosa, deliciosa, sabor'
数据准备:
为每组单词 ($grouped
) 形成一个管道分隔的捕获组数组——这些字符串将构成正则表达式模式的中心部分。
形成一个数组,其中子数组值成为各自的子键——这将使访问随机替换词 simpler/cleaner。
形成一个正则表达式模式,将管道分隔、括号包裹的字符串与更多管道粘合在一起,然后用非捕获组包裹该字符串,然后用单词边界包裹它,以便只整个单词匹配。示例数据的生成模式是:
/\b(?:(sabor|gosto|delicia)|(saborosa|gostosa|deliciosa))\b/
替换执行:
使用生成的模式匹配 $myWords
和 $flipped
查找数组中任何子数组的整个单词,自定义回调将接收匹配值数组。
$m[0]
将是全字符串匹配。虽然它包含所需的值,但它不会告诉我们匹配来自哪个子数组。因此,数组中省略了 $m[0]
。
如果匹配的词来自第一组词,那么$m[1]
将有一个非空字符串。这个捕获的单词将从 $flipped
中删除,以消除用自己替换自己的可能性。
最后,array_rand()
用于从相关子数组中提取剩余单词之一。此随机选择成为用作替换的词。
哦,回调中的 foreach()
会一直迭代,直到找到一个非空字符串。换句话说,如果捕获的词在第二个子数组中,它会忽略[0]
(当$i === 0
时,然后在$i === 0
时采取行动。
preg_replace_callback()
没有指定限制,因此它会尽可能多地进行替换,但只会对字符串进行一次传递。这意味着它不会替换替代品。
$myVar = 'essa pizza é muito gostosa';
$myWords=array(
array('sabor','gosto','delicia'),
array('saborosa','gostosa','deliciosa'),
);
foreach($myWords as $words){
// randomize the subarray
shuffle($words);
// pipe-together the words and return just one match
if(preg_match('/\b\K'.implode('|',$words).'\b/',$myVar,$out)){
// generate "replace_pair" from matched word and a random remaining subarray word
// replace and preserve the new sentence
$myVar=strtr($myVar,[$out[0]=>current(array_diff($words,$out))]);
}
}
echo $myVar;
应替换为:
$myVar = 'essa pizza é muito deliciosa';
或
$myVar = 'essa pizza é muito saborosa';
但是您正在换取较小的单词键,只是因为这个较小的键也包含这个较大键的所有字母!
正在发生的输出是错误的:
$myVar = 'essa pizza é muito saborsa';
"saborsa"(这个词在葡萄牙语和我的数组中都不存在)!
正在切字"gostosa",放字"sabor" 然后,不是输入单词 "saborosa," 而是形成不存在的单词:"saborsa"。 word "gostosa" = "sa" + word "sabor" = "saborsa" 的一部分(这个词不存在)必须是 "saborosa".
最大的问题是将单词 "gostosa" 的一部分视为单词 "gosto"
如何在替换之前阅读完整的关键字/单词? 谢谢
多年后我才看到我原来的答案,并意识到它不是为了进行多次随机替换而构建的。我删除了旧答案,用更可靠的技术取而代之。
代码:(Demo)
$myVar = 'essa pizza é muito gostosa, gostosa, gostosa, gosto';
$myWords = [
['sabor', 'gosto', 'delicia'],
['saborosa', 'gostosa', 'deliciosa'],
];
$grouped = [];
$flipped = [];
foreach ($myWords as $row) {
$grouped[] = '(' . implode('|', $row) . ')';
$flipped[] = array_flip($row);
}
$pattern = '/\b(?:' . implode('|', $grouped) . ')\b/';
var_export(
preg_replace_callback(
$pattern,
function($m) use ($flipped) {
array_shift($m);
foreach ($m as $i => $captured) {
if ($captured) {
unset($flipped[$i][$captured]);
return array_rand($flipped[$i]);
}
}
},
$myVar
)
);
潜在产出:
'essa pizza é muito deliciosa, saborosa, deliciosa, sabor'
数据准备:
为每组单词 (
$grouped
) 形成一个管道分隔的捕获组数组——这些字符串将构成正则表达式模式的中心部分。形成一个数组,其中子数组值成为各自的子键——这将使访问随机替换词 simpler/cleaner。
形成一个正则表达式模式,将管道分隔、括号包裹的字符串与更多管道粘合在一起,然后用非捕获组包裹该字符串,然后用单词边界包裹它,以便只整个单词匹配。示例数据的生成模式是:
/\b(?:(sabor|gosto|delicia)|(saborosa|gostosa|deliciosa))\b/
替换执行:
使用生成的模式匹配 $myWords
和 $flipped
查找数组中任何子数组的整个单词,自定义回调将接收匹配值数组。
$m[0]
将是全字符串匹配。虽然它包含所需的值,但它不会告诉我们匹配来自哪个子数组。因此,数组中省略了 $m[0]
。
如果匹配的词来自第一组词,那么$m[1]
将有一个非空字符串。这个捕获的单词将从 $flipped
中删除,以消除用自己替换自己的可能性。
最后,array_rand()
用于从相关子数组中提取剩余单词之一。此随机选择成为用作替换的词。
哦,回调中的 foreach()
会一直迭代,直到找到一个非空字符串。换句话说,如果捕获的词在第二个子数组中,它会忽略[0]
(当$i === 0
时,然后在$i === 0
时采取行动。
preg_replace_callback()
没有指定限制,因此它会尽可能多地进行替换,但只会对字符串进行一次传递。这意味着它不会替换替代品。