【问题标题】:Extraneous Empty Trailing Match无关的空尾随匹配
【发布时间】:2016-11-11 16:59:54
【问题描述】:

我正在尝试创建一个用于拆分字符串的正则表达式,但不幸的是,我的要求比简单拆分要复杂一些,因此我不能在 PHP 中使用例如 preg_split()

所以我正在做的是在一个子表达式中匹配我的分隔符(或者更确切地说是其中的一部分),以及在另一个子表达式中匹配它之前的所有内容,并将字符串的结尾视为一个分隔符。 .考虑到这一点,我想出了以下内容:

([^?;]*)(?|\?([0-9]*)|(;)|$)

如您所见,第一个子模式会查找没有任何分号问号的文本块。在此之后,我有一个子模式匹配任何问号与之后的可选数字(存储),或者是分号(存储)或字符串的结尾。

问题是我似乎得到了一个无关紧要的空匹配字符串大小写,如下所示:

$sql = 'CALL foo(?0, ?1, ?2, ?3)';
preg_match_all('/([^?;]*)(?|\?([0-9]*)|(;)|$)/', $sql, $matches);
print_r($matches);

生成如下所示的输出:

Array
(
    [0] => Array
        (
            [0] => CALL insert_host(?0
            [1] => , ?1
            [2] => , ?2
            [3] => , ?3
            [4] => )
            [5] => 
        )

    [1] => Array
        (
            [0] => CALL insert_host(
            [1] => , 
            [2] => , 
            [3] => , 
            [4] => )
            [5] => 
        )

    [2] => Array
        (
            [0] => 0
            [1] => 1
            [2] => 2
            [3] => 3
            [4] => 
            [5] => 
        )

)

注意$matches[0][5]下的空匹配;我本来希望在匹配括号后满足字符串大小写的结尾,导致没有进一步的匹配,但它继续产生另一个匹配,我不知道为什么。

所以我的问题是;为什么这里会产生额外的匹配,我该如何防止它?

注意:我已经考虑过要求字符串大小写的结尾至少有一个字符,但这并不好,因为如果通配符是,我实际上想要一个空结果在字符串的 处,因为我正在尝试模拟拆分函数的行为。例如,如果输入是SELECT ?,我希望匹配SELECT ? 加上一个空字符串。这里的想法是,一旦我处理了任何匹配的分号,我就可以简单地使用implode('?', $matches[1]) 来重现带有数字通配符的语句。

【问题讨论】:

    标签: php regex


    【解决方案1】:

    我相信我可能已经找到了替代我的具体案例的方法来解决问题;我所做的是翻转表达式,以便首先匹配分隔符,否则,匹配字符串的开头,如下所示:

    (?|\?([0-9]*)|(;)|^)([^?;]*)
    

    这在所有情况下都会产生预期的结果:

    preg_match_all('/(?|\?([0-9]*)|(;)|^)([^?;]*)/', 'CALL foo(?3, ?2, ?1, ?0)', $matches);
    print_r($matches);
    

    生产:

    Array
    (
        [0] => Array
            (
                [0] => CALL foo(
                [1] => ?3, 
                [2] => ?2, 
                [3] => ?1, 
                [4] => ?0)
            )
        [1] => Array
            (
                [0] => 
                [1] => 3
                [2] => 2
                [3] => 1
                [4] => 0
            )
    
        [2] => Array
            (
                [0] => CALL foo(
                [1] => , 
                [2] => , 
                [3] => , 
                [4] => )
            )
    )
    

    同时:

    preg_match_all('/(?|\?([0-9]*)|(;)|^)([^?;]*)/', 'SELECT ?', $matches);
    print_r($matches);
    

    生产:

    Array
    (
        [0] => Array
            (
                [0] => SELECT 
                [1] => ?
            )
        [1] => Array
            (
                [0] => 
                [1] => 
            )
        [2] => Array
            (
                [0] => SELECT 
                [1] => 
            )
    )
    

    但是,这只是因为我知道输入永远不会包含分隔符作为第一个字符;如果我提供一个,它会遇到同样的问题,所以我不确定是否称它为真正的解决方案。

    我仍然很想知道为什么我的原始表达式得到了额外的匹配,因为我原以为贪婪匹配意味着它是不可能的,因为一旦匹配字符串的结尾,就应该没有什么可以找到了.

    【讨论】:

      猜你喜欢
      • 2017-05-21
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-24
      相关资源
      最近更新 更多