当前位置: 首页 > 知识库问答 >
问题:

PHP RegExpreg_match_all在当前匹配之前重复匹配的单词

齐琦
2023-03-14

我有以下正则表达式代码

$str = 'word1 word2 word3 keyword word4 word5 word6 keyword word7 word8 word9 word10';
$matches = array();
preg_match_all('/(\w* ){1,3}keyword( \w*){1,3}/u', $str, $matches);

我希望比赛包括:

word1 word2 word3关键字word4 word5 word6

word4 word5 word6关键字word7 word8 word9

但实际上,我得到的是:

word1 word2 word3关键字word4 word5 word6

关键字word7 word8 word9

换句话说,第二场比赛因第一场比赛而被裁切。

这是一个测试:https://regex101.com/r/EPp14b/1/

共有3个答案

阴凯歌
2023-03-14

您需要的整个部分(周围的关键字)都在前瞻性断言中的捕获组(结果)中,这样字符就不会被使用,并且可以在以后的最终下一个匹配中使用。但是为了避免多次匹配同一个关键字,您需要到达该关键字之后的位置,并使用所有字符,直到包含该关键字为止。这就是为什么我定义了一个名为consume的组,并引用了他的内容:\g{consume}

$pattern = '~
\b
(?=
    (?<result>
        (?<consume>
           (?> \w+ \h+ ){0,3}?
           keyword \b
        )
        (?: \h+ (?! keyword \b ) \w+ ){0,3}
    )
) \g{consume}
~ux';

演示

使用此模式,您不必重新构建结果,所有结果都存储在命名的组结果中:

preg_match_all($pattern, $str, $matches);

print_r($matches['result']);
慕志泽
2023-03-14

如果您不想跨越关键字,可以在重复1-3个单词时使用否定的前瞻性来断言它们不是关键字。

匹配后,您可以对捕获组使用积极的前瞻性断言,匹配1-3个不是关键字的单词

这句话将是完全匹配和组1的串联。

(?<!\S)(?:(?!keyword\b)\w+\h+){1,3}keyword\b(?=((?:\h+(?!keyword\b)\w+){1,3}))

模式匹配:

  • <代码>(?
  • 捕获组1
    • (?:\h(?! keyword\b)\w){1,3}匹配1-3个不以keyword开头的词

    正则表达式演示|Php演示

    $re = '/(?<!\S)((?:(?!keyword\b)\w+\h+){1,3}keyword\b)(?=((?:\h+(?!keyword\b)\w+){1,3}))/u';
    
    $strings = [
        "word1 word2 word3 keyword word4 word5 word6 keyword word7 word8 word9 word10",
        "word2 keyword word4 word5 word6 keyword word7 word8",
        "word2 word3 keyword word4 word5 word6 keyword word7 keyword word10",
    ];
    
    foreach ($strings as $str) {
        preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
        $matches = array_map(function($m) {
            return $m[1] . $m[2];
        }, $matches);
        print_r($matches);
    }
    

    输出

    Array
    (
        [0] => word1 word2 word3 keyword word4 word5 word6
        [1] => word4 word5 word6 keyword word7 word8 word9
    )
    Array
    (
        [0] => word2 keyword word4 word5 word6
        [1] => word4 word5 word6 keyword word7 word8
    )
    Array
    (
        [0] => word2 word3 keyword word4 word5 word6
        [1] => word4 word5 word6 keyword word7
        [2] => word7 keyword word10
    )
    

王炜
2023-03-14

另一种选择是将完整匹配放在前瞻内的捕获组中,以便能够获得重叠匹配:

(?=((\b(?:\w+\h+){1,3}keyword)(?:\h+\w+){1,3}))(?2)

RegEx演示

代码:

$s = 'word1 word2 word3 keyword word4 word5 word6 keyword word7 word8 word9 word10';
$re = '/(?=((\b(?:\w+\h+){1,3}keyword)(?:\h+\w+){1,3}))(?2)/u';
preg_match_all($re, $s, $m);
print_r($m[1]);

/* Output
Array
(
    [0] => word1 word2 word3 keyword word4 word5 word6
    [1] => word4 word5 word6 keyword word7 word8 word9
)
*/

正则表达式详细信息:

  • (? =:开始前瞻
    • :开始捕获组#1
      • :开始捕获组#2
        • \b:单词边界
        • (?:\w\h){1,3}:匹配1到3个单词
        • 关键字

 类似资料:
  • 我是不是漏掉了什么?提前感谢!

  • 问题内容: 我想在查询上使用模糊匹配,但在结果顶部显示完全匹配。 我已经尝试了以下方法。 由于格式错误的查询错误,此方法不起作用。 有任何想法吗? 问题答案: 我最终没有使用模糊匹配来解决我的问题,而是使用了ngram。 结果正是我想要的。它根据搜索查询中包含的ngram部分构造匹配项。

  • 在PostgreSQL中获得最长前缀匹配的准确快速查询的最佳方法是什么? 是: 我计划在更新中使用。有什么想法吗?

  • 我在列表中有这样的数据: 我当前的解决方案能够检测到完全匹配的重复项。因此,它当前将输出: 我想增加一些可能性,以便它们也在输出列表中: 下面是我当前的代码: 我将非常感谢任何善意的建议,以导致实现这种检查的解决办法?我个人认为这里没有任何可能的合乎逻辑的解决办法?也许只是某种基于分数的Levenshtein距离计算和检测?如果这是不可能的,将是有益的,至少得到这些(匹配多个单词,例如两个):

  • 我正在尝试执行一个bash文件,该文件执行以下操作: 从文件夹中,仅提取文件名中包含干净单词的文件夹。 从这些中,如果其中有一个1,那么取那个和下面的。 现在,我站在这一点上: 我对if语句有问题,因为我不知道如何表达它 谢谢

  • foo-bar-herp foo-bar-derp baz-blub其他东西 我想提供一个搜索工作,以便 “foo bar”(标记化前缀) “Foo Herp”(跳过令牌) “foo-bar-”(确切的前缀) “bar-herp”(中间的确切字符串) “foo ba”(一个完整的令牌和另一个令牌的前缀) null