You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PHP正则匹配目标词在指定距离内无特定词的句子?

用PHP正则实现「含目标词但排除特定邻近词(指定词距)」的句子匹配

这问题我之前做文本过滤时刚好碰到过,核心就是正向匹配目标词 + 负向环视排除特定邻近范围的词,用PHP的PCRE正则就能完美解决,我给你拆解思路和具体实现:

核心思路

我们需要两步逻辑:

  1. 确保句子里包含完整的目标词(避免部分匹配,比如news里的new)
  2. 用负向前瞻/后瞻,检查目标词前后N个词的范围内,是否存在需要排除的前置/后置词——如果存在,就跳过这个句子;如果不存在,就匹配成功

具体实现(可直接复用)

1. 配置参数

先把可变的条件抽成参数,方便后续调整:

<?php
// 目标词:我们要找的词
$targetWord = 'new';
// 排除后置词:目标词后N词内不能出现的词
$excludeAfterWords = ['york', 'delhi'];
// 排除前置词:目标词前N词内不能出现的词
$excludeBeforeWords = ['old', 'used'];
// 最大词距:比如设置2,就是目标词前后最多2个词的范围(0=紧邻,1=隔1个词,以此类推)
$maxWordDistance = 2;

2. 构建正则表达式

这里要注意转义正则特殊字符,避免词里有+*?这类符号导致正则出错:

// 转义排除词并拼接成正则分支(比如变成york|delhi)
$excludeAfterPattern = implode('|', array_map('preg_quote', $excludeAfterWords));
$excludeBeforePattern = implode('|', array_map('preg_quote', $excludeBeforeWords));

// 拼接最终正则
$regex = sprintf(
    '~^.*\b(%s)\b(?!(?:\W+\w+){0,%d}\W+(?:%s))(?<!(?:\W+\w+){0,%d}\W+(?:%s)).*$~i',
    preg_quote($targetWord),
    $maxWordDistance,
    $excludeAfterPattern,
    $maxWordDistance,
    $excludeBeforePattern
);

3. 测试匹配

拿一组句子测试看看效果:

$sentences = [
    "I bought a new car yesterday.",          // ✅ 匹配:new前后无排除词
    "I'm visiting New York next week.",        // ❌ 不匹配:new后1词是york
    "She found a new apartment near old town.",// ✅ 匹配:old在new后超过2词距
    "Old new stock is not worth buying.",      // ❌ 不匹配:old在new前紧邻
    "Looking for new books about new delhi."   // ✅ 匹配:第一个new符合条件(第二个new虽不符合,但句子存在有效匹配)
];

// 遍历匹配
foreach ($sentences as $sentence) {
    $matches = [];
    if (preg_match($regex, $sentence, $matches)) {
        echo "匹配成功:{$sentence}\n";
    } else {
        echo "匹配失败:{$sentence}\n";
    }
}

关键细节解释

  • \b:词边界,确保我们匹配的是完整的new,而不是news、renew这类词里的片段
  • (?:\W+\w+){0,$maxDistance}:匹配0到N个“分隔符+单词”的组合,也就是目标词前后最多N个词的范围。\W+负责匹配空格、逗号等分隔符,\w+匹配单词本身
  • (?!...):负向前瞻,检查目标词后面N词内没有排除的后置词
  • (?<!...):负向后瞻,检查目标词前面N词内没有排除的前置词
  • preg_quote():转义目标词和排除词里的正则特殊字符(比如如果目标词是new?,会自动转义?避免正则语法错误)
  • 修饰符i:忽略大小写,如果你需要区分大小写,可以去掉这个修饰符

进阶场景:要求所有目标词都不能有排除词

上面的代码是只要句子里有一个符合条件的目标词就匹配,如果你的需求是句子里所有目标词都不能在N词距内出现排除词,可以用下面的正则:

$regexStrict = sprintf(
    '~^(?!.*\b(%s)\b(?=(?:\W+\w+){0,%d}\W+(?:%s)))(?!.*(?<=(?:\W+\w+){0,%d}\W+(?:%s))\b(%s)\b).*\b(%s)\b.*$~i',
    preg_quote($targetWord),
    $maxWordDistance,
    $excludeAfterPattern,
    $maxWordDistance,
    $excludeBeforePattern,
    preg_quote($targetWord),
    preg_quote($targetWord)
);

用这个正则的话,上面测试用的Looking for new books about new delhi.就会匹配失败,因为句子里有一个new后面跟着delhi。

内容的提问来源于stack exchange,提问作者Sathishkumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:04:03