用分组单词数组中的随机单词替换字符串中的整个单词

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'

数据准备:

  1. 为每组单词 ($grouped) 形成一个管道分隔的捕获组数组——这些字符串将构成正则表达式模式的中心部分。

  2. 形成一个数组,其中子数组值成为各自的子键——这将使访问随机替换词 simpler/cleaner。

  3. 形成一个正则表达式模式,将管道分隔、括号包裹的字符串与更多管道粘合在一起,然后用非捕获组包裹该字符串,然后用单词边界包裹它,以便只整个单词匹配。示例数据的生成模式是:

    /\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() 没有指定限制,因此它会尽可能多地进行替换,但只会对字符串进行一次传递。这意味着它不会替换替代品。