2

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

每个条目必须以 开头并至少包含type/subtype,可以选择使用+basetype 例如text/htmlapplication/xhtml+xml 条目以逗号分隔。在初始 之后type/subtype,该条目可能包含可变数量的参数key=value对,以分号分隔(分号之间允许空格,但对之间不允许空格=key=value例如application/xhtml+xml; q=0.8; test=hello

我想将所有这些信息放入一个数组中。

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

当与标题字符串一起使用时,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=value一个条目 ( application/xhtml+xml; q=0.9; level=3) 只给出了最后一个,q=0.9缺少 。

有什么方法可以在每个匹配项中包含所有(可变数量)参数,同时仍然只使用一个正则表达式,还是我必须为这些对使用单独的正则表达式/函数key=value

编辑:

我想要的数组结果是这样的(显然,每种内容类型的项目 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 
        )

)

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

编辑

我已经接受了Ka的回答,这似乎给了我所需要的一切。(?:\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 的数组来确定各个内容类型及其参数之间的边界。

非常感谢 Ka 的帮助。

编辑:

再次更改了表达式 - 表达式还需要能够解析通配符 mime,例如text/*. 所以现在的表达式变成了:

(?:\G\s?,\s?|^)(\w+|\*)\/(\w+|\*)(?:\+(\w+))?|(?<!^)\G(?:\s?;\s?(\w+)=([\w\.]+))
4

2 回答 2

3

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

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

尤其是针对您的情况:

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

于 2013-03-18T09:20:10.817 回答
1

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

正则表达式:((\w+)\/(\w+)(?:\+(\w+))?|(?:\s?;\s?(\w+)=([\w\.]+)) 带有全局标志g
解释演示: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

更新:

使用全局标志g
正则 表达式同时进行验证和捕获:(\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字符集,请在此处解释。如果您允许使用此正则表达式将一些不必要的数据保存在数组中,甚至更短:

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

((?4))?并根据需要重复,请参见此处

于 2013-03-18T13:59:57.193 回答