代码之家  ›  专栏  ›  技术社区  ›  Rupert

如何更正此正则表达式以捕获PHP中所有重复的参数组?

  •  2
  • Rupert  · 技术社区  · 12 年前

    我正在尝试解析HTTP Accept标头,以从中提取所有细节。 我做出以下假设:

    每个条目必须以开头并至少包含 type/subtype ,可选带有 +basetype 例如 text/html application/xhtml+xml 条目用逗号分隔。 在初始 类型/子类型 ,该条目可能包含可变数量的参数 key=value 对,用分号分隔(分号之间允许空白,但分号之间不允许空白 = 属于 key=值 成对) 例如 application/xhtml+xml; q=0.8; test=hello

    我想把所有这些信息都放到一个数组中。

    我现在拥有的是 preg_match_all('/([^,;\/=\s]+)\/([^,;\/=\s+]+)(\+([^,;\/=\s+]+))?(\s?;\s?([^,;=]+)=([^,;=]+))*/', $header, $result, PREG_SET_ORDER); 在我看来,它给出了一个带有类型的初始捕获组,然后是一个带有子类型的捕获组,再是一个带基本类型的可选捕获组,最后是一个可选重复捕获组,由 ; ,包含两个 key=值 .

    与标题字符串一起使用时 application/xhtml+xml; q=0.9; level=3 , text/html,application/json;test=hello 这给了我:

    Array
    (
        [0] => Array
            (
                [0] => application/xhtml+xml; q=0.9; level=3 
                [1] => application
                [2] => xhtml
                [3] => +xml
                [4] => xml
                [5] => ; level=3 
                [6] => level
                [7] => 3 
            )
    
        [1] => Array
            (
                [0] => text/html
                [1] => text
                [2] => html
            )
    
        [2] => Array
            (
                [0] => application/json;test=hello 
                [1] => application
                [2] => json
                [3] => 
                [4] => 
                [5] => ;test=hello 
                [6] => test
                [7] => hello 
            )
    
    )
    

    除了最后一个 key=值 为第一个条目提供( application/xhtml+xml; q=0.9; level=3 ) q=0.9 缺少。

    是否有任何方法可以在每次匹配中包含所有(可变数量)参数,同时仍然只使用一个正则表达式,或者是否必须为 key=值 对?

    编辑:

    我想要的数组结果是这样的(显然,每种内容类型的项0、3、5、8…等是不必要的,但我不知道是否可以排除它们):

    Array
    (
        [0] => Array
            (
                [0] => application/xhtml+xml; q=0.9; level=3 
                [1] => application
                [2] => xhtml
                [3] => +xml
                [4] => xml
                [5] => ; q=0.9 
                [6] => q
                [7] => 0.9 
                [8] => ; level=3 
                [9] => level
               [10] => 3 
            )
    
        [1] => Array
            (
                [0] => text/html
                [1] => text
                [2] => html
            )
    
        [2] => Array
            (
                [0] => application/json;test=hello 
                [1] => application
                [2] => json
                [3] => 
                [4] => 
                [5] => ;test=hello 
                [6] => test
                [7] => hello 
            )
    
    )
    

    这使我可以获取每个参数的键和值,而无需执行任何进一步的regexp或字符串函数。

    编辑

    我已经接受了 灵魂 的答案,这似乎给了我所需要的一切。 使用他的模式 (?:\G\s?,\s?|^)(\w+)\/(\w+)(?:\+(\w+))?|(?<!^)\G(?:\s?;\s?(\w+)=([\w\.]+)) 在相同的字符串上(没有设置的顺序)给出结果:

    Array
    (
        [0] => Array
            (
                [0] => application/xhtml+xml
                [1] => ; q=0.9
                [2] => ; level=3
                [3] =>  , text/html
                [4] => ,application/json
                [5] => ;test=hello
            )
    
        [1] => Array
            (
                [0] => application
                [1] => 
                [2] => 
                [3] => text
                [4] => application
                [5] => 
            )
    
        [2] => Array
            (
                [0] => xhtml
                [1] => 
                [2] => 
                [3] => html
                [4] => json
                [5] => 
            )
    
        [3] => Array
            (
                [0] => xml
                [1] => 
                [2] => 
                [3] => 
                [4] => 
                [5] => 
            )
    
        [4] => Array
            (
                [0] => 
                [1] => q
                [2] => level
                [3] => 
                [4] => 
                [5] => test
            )
    
        [5] => Array
            (
                [0] => 
                [1] => 0.9
                [2] => 3
                [3] => 
                [4] => 
                [5] => hello
            )
    
    )
    

    从中,我可以使用索引1的数组编译关联数组,以确定具有其参数的各个内容类型之间的边界。

    非常感谢卡的帮助。

    编辑:

    再次更改了表达式-该表达式还需要能够解析通配符mimes,例如 text/* . 因此,表达式现在变成:

    (?:\G\s?,\s?|^)(\w+|\*)\/(\w+|\*)(?:\+(\w+))?|(?<!^)\G(?:\s?;\s?(\w+)=([\w\.]+))
    
    2 回复  |  直到 12 年前
        1
  •  3
  •   starshine531    12 年前

    我建议您使用php的解析函数,而不是尝试编写自己的解析函数。

    有关详细信息,请参阅: http://php.net/manual/en/ref.http.php

    尤其是针对您的情况:

    http://php.net/manual/en/function.http-parse-headers.php

        2
  •  1
  •   CSáµ    12 年前

    与您想要的输出略有不同,但可以安全地获得所有值,而不需要您不需要的值:

    注册交易所: (\w+)\/(\w+)(?:\+(\w+))?|(?:\s?;\s?(\w+)=([\w\.]+)) (带有全球标志 )
    演示说明: http://regex101.com/r/fM1gJ2
    编辑:这更好地用于已经验证的头,因为它是用正则表达式组成的 or ,您可以使用此正则表达式 \w+\/\w+(\+\w+)?(\s?;\s?\w+=[\w\.]+)* 以进行验证。

    大致如下:

    注册交易所: (\w+)\/(\w+)(?:\+(\w+))?(?:\s?;\s?(\w+)=([\w\.]+))?
    最后一部分 (?:\s?;\s?(\w+)=([\w\.]+))? 重复你认为必须重复的次数
    演示: http://regex101.com/r/yI6uS1

    更新:

    使用全局标志同时进行验证和捕获
    注册交易所: (\w+)\/(\w+)(?:\+(\w+))?|(?<!^)\G(?:\s?;\s?(\w+)=([\w\.]+))
    演示说明如下: http://regex101.com/r/bR7kU2
    使现代化 (内容类型必须始终用逗号分隔)
    注册交易所: (?:\G\s?,\s?|^)(\w+)\/(\w+)(?:\+(\w+))?|(?<!^)\G(?:\s?;\s?(\w+)=([\w\.]+)) 演示: http://regex101.com/r/nG4oV0

    以及v2的较短重复结束模式: (?:\s?;\s?((?4))=((?5)))? 以防您增加 key=value 字符集, explained here 。或者更短,如果您允许使用此regex将一些不必要的数据保存在数组中:

    (\w+)\/(\w+)(?:\+(\w+))?(\s?;\s?([\w-]+)=([\w!:\$\.-]+))?((?4))?
    

    并重复 ((?4))? 根据需要, see it here .