需要使用自定义同义词替换文本中的单词

时间:2013-07-08 20:51:02

标签: php regex

$string='print the imprint with the imprinted printing paper';

$pattern=array('/print/','/imprint/','/paper/',);
$replacement=array('imprint','print','machine');

输出:

print the imprint with the imprinted printing machine

我认为我理解正确的前两种模式相互重叠。我想让这个更复杂,但REGEX仍然是我的伏都教。显示输入字符串后,我想回复一下:imprint the print with the printed imprinting machine。如果我还能看到如何输出imprint the print with the imprinted printing machine,那也会很棒。

如果你能解释一下你的正则表达式,那会更有帮助。也许我以后可以自己做更多的事情。

2 个答案:

答案 0 :(得分:4)

在单个正则表达式中完成所有这些替换,并且您没问题,因为在一次传递中,正则表达式将在一次替换后继续,并且不会再次尝试与替换匹配:

$string = 'print the imprint with the imprinted printing paper';

// A single array of find => replace
$replacements = array( 
    'print'   => 'imprint', 
    'imprint' => 'print', 
    'paper'   => 'machine'
);

// Dynamically form the regex, properly escaping it
$delimiter = '/';
$words = array_keys( $replacements);
$regex = $delimiter . '\b(' . implode('|', array_map( 'preg_quote', $words, array_fill( 0, count( $words), $delimiter))) . ')\b' . $delimiter;

形成的正则表达式如下所示:

/\b(print|imprint|paper)\b/

其中:

  1. \b是一个单词边界。
  2. ()是一个捕获组。
  3. print|imprint|paper是一个或匹配其中一个
  4. 最后,要做替换:

    $result = preg_replace_callback( $regex, function( $match) use( $replacements) {
        return $replacements[$match[1]];
    }, $string);
    echo $result;
    

    will output

    imprint the print with the printed imprinting machine
    

答案 1 :(得分:2)

如果您需要进行直接的字符串替换,而不是多次重复结果字符串,则应使用strtr()代替:

strtr($string, array(
    'imprint' => 'print',
    'print' => 'imprint',
    'paper' => 'machine',
));

要替换的单词按字符串长度排序,最具体的是第一个。

注意:这当然不像正则表达式那样灵活,特别是当它只替换完整的单词时,即/\bword\b/仅匹配word时才会匹配;这不是你可以用strtr()和朋友做的事情。

使用正则表达式

要使preg_replace()只对字符串执行一次传递,您需要将替换键组合成一个表达式,即

/imprint|print|paper/

此表达式使用交替,由搜索字符串之间的管道字符影响。要仅匹配整个单词,您需要添加边界匹配,一个特殊的\b序列,匹配单词和非单词之间的过渡。

/\b(?:imprint|print|paper)\b/

这将匹配"imprint"但不匹配"pimprint"

如果您沿着这条路线行驶,则需要使用preg_replace_callback()执行更换;对于每个匹配,它会找到一个自定义函数,您可以在其中确定要替换它的内容。你需要为它创建一个替换地图,就像我之前用于strtr()示例的地图一样。

$map = array(
    'imprint' => 'print',
    'print' => 'imprint',
    'paper' => 'machine',
);

$replacer = function($match) use ($map) {
    // $match[0] holds the found word
    return $map[$match[0]];
};

preg_replace_callback('/\b(?:imprint|print|paper)\b/', $string, $replacer);

让它变得动态

我已经手动创建了正则表达式,但为了使其灵活,您需要根据替换映射动态生成它。为此,我们需要:

  1. 从替换地图中提取密钥;
  2. 逃避任何特殊字符;
  3. 构建最终表达。
  4. 这就是构建表达式的方法:

    // step 1
    $replacement_keys = array_keys($map);
    // step 2
    $escaped_keys = array_map(function($key) {
        return preg_quote($key, '/');
    }, $replacement_keys);
    // step 3
    $pattern = '/\b(?:' . join('|', $escaped_keys) . ')\b/';