如何从字符串中删除(大多数)短单词

3

我目前使用以下正则表达式从字符串中删除长度小于4个字符的单词。

$dirty = "I welcome you to San Diego";
$clean = preg_replace("/\b[^\s]{1,3}\b/", "", $dirty);

因此,这将导致“欢迎Diego”;

然而,现在我需要忽略某些单词的替换,例如:

$ignore = array("San", "you");

会导致"欢迎您圣地亚哥"的结果。

1
大多数搜索引擎通过指定“停用词”黑名单来处理此问题。http://armandbrahaj.blog.al/2009/04/14/list-of-english-stop-words/ - Frank Farmer
[^\s] 用于代替 \S,你是否意识到 \b 的定义不是基于 \S\s,而是仅基于 \w - tchrist
2个回答

9

您可以使用(?!..)负向断言来嵌入您的忽略列表:

 preg_replace("/\b(?!San|you|not)\w{1,3}\b/", "", ...

我建议使用\w 而不是 [^\s],以便只匹配单词。

2
这似乎比回调函数更优雅,并且很可能性能更好。 - Halcyon
1
@Frits:在这里嵌入一个以|分隔的单词列表也更容易。但是无论如何,我还是点赞了回调函数的替代方案;}即使只是因为我认为preg_replace_callback提及得太少了。 - mario
@Frits:确实,唯一的“缺点”就是在将单词列表通过preg_quote运行之前应该使用|进行拼接,但这也可以在一行中使用array_map完成,所以这并不是一个大问题。不知道为什么这个答案没有被接受。 - Alix Axel

5

我建议使用回调函数 (preg_replace_callback),因为它可以提供更具可维护性的解决方案,如果你需要处理大量的单词:

echo preg_replace_callback(
    '/\b[^\s]{1,3}\b/',
    create_function(
        '$matches',
        '$ignore = array("San", "you");
         if (in_array($matches[0], $ignore)) {
            return $matches[0];
         } else {
            return \'\';
         }'
    ),
    "I welcome you to San Diego"
); 
// output: welcome you San Diego 

如果您使用的是 PHP 5.3 或更高版本,可以使用匿名函数代替调用 create_function


请记住,create_function会产生已知的内存泄漏问题。最好避免使用它。 - Halcyon
我认为你想要的是 \b\w{1,3}\b - tchrist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接