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

Posted

技术标签:

【中文标题】用一组单词数组中的随机单词替换字符串中的整个单词【英文标题】:Replace whole words in a string with a random word from an array of grouped words 【发布时间】:2017-11-03 09:32:24 【问题描述】:
$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”。 "gostosa" = "sa" + word "sabor" = "saborsa"(这个词不存在)的一部分必须是 "saborosa"。

最大的问题是把“gostosa”这个词的一部分看作是“gosto”这个词

在替换之前如何阅读完整的键/词? 谢谢

【问题讨论】:

我现在已经对这个问题的解释进行了细化,解释了系统从数组中找到一个单词时的效果,在$myVar中较大的单词的一部分中。 【参考方案1】:

事实发生多年后,我遇到了我的原始答案,并意识到这不是为了进行多次随机替换而构建的。我已经清除了旧答案,用更强大的技术替换它。

代码:(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) 形成一个以竖线分隔的捕获组数组——这些字符串将构成正则表达式模式的中心部分。

    形成一个数组,其中子数组的值成为相应的 subartay 键——这将使访问随机替换词更简单/更清晰。

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

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

【讨论】:

以上是关于用一组单词数组中的随机单词替换字符串中的整个单词的主要内容,如果未能解决你的问题,请参考以下文章

如何用ruby中的数组中的元素替换字符串中的单词?

如何用非重音字符替换clickhouse中数组中的每个单词的每个重音字符?

如何确保 replaceAll 将替换整个单词而不是子字符串

将整个单词与字符串中的前导或尾随特殊符号(如美元)匹配

选择多个用数组中的每个值替换一个单词

替换出现在两个特定单词之间的一组字符串的所有出现