【问题标题】:regex matching url正则表达式匹配网址
【发布时间】:2013-04-13 00:17:44
【问题描述】:

在 PHP 中,klein 路由将匹配尽可能多的路由。 我设置的 2 条路线相互冲突。它们是:

$route1: '/websites/[i:websiteId]/users/[i:id]?'

$route2: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]?'

这是我要匹配的 URL,我认为应该匹配第一个而不是第二个,是:

/api/v1-test/websites/100/users/4

为这两个生成的正则表达式是:

$regex1: `^/api(?:/(v1|v1-test))/websites(?:/(?P<websiteId>[0-9]++))/users(?:/(?P<id>[0-9]++))?$`

$regex2: `^/api(?:/(v1|v1-test))/websites(?:/(?P<websiteId>[0-9]++))/users(?:/(?P<filename>[0-9A-Za-z]++))(?:\.(?P<extension>json|csv))?$`

如果没有“.csv”或“.json”,我的意思是它不匹配。问题是它匹配两条路线。对于第二个,生成的文件名是“4”,扩展名是空白的。

发送 /api/v1-test/websites/100/users/users.csv 可以正常工作,并且只匹配第二个路由。

我只能控制路由,而不是正则表达式或匹配。 谢谢。

【问题讨论】:

    标签: php regex routing


    【解决方案1】:

    这里有点

    (?:\.(?P<extension>json|csv))?
    

    在第二个正则表达式的末尾,由于末尾的 ? 导致它匹配是否存在文件名。问号表示0 or 1 of the previous expression。摆脱它,至少,字符串只有在具有扩展名时才会匹配这个正则表达式。

    要进行此更改,只需从您的第二条路线中删除问号,如下所示:

    $route2: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]'
    

    【讨论】:

    • 当我第一次阅读这个答案时,我不太喜欢它。我的天真理解是?表示在此之后的任何内容都被视为参数。
    • 你说得对吗?可用于label a subpattern。但碰巧在 PHP 正则表达式语法(Klein 路由系统使用)中,问号有不止一种用途。最后 ?在您的路线中被解释为0 or 1 meta character
    • 事实上,Klein readme 中的最后一个路由示例与您描述的路由非常相似,明确表示它会导致选项文件扩展名。如果您希望 route2 需要扩展,则应删除尾随 ?
    • 抱歉,在我写完之后我的键盘就被锁住了,我没有完成我的想法。将其更改为 [json|csv:extension]+?修复它。所以你是对的。
    • @BradWhite:当 url 看起来像 /api/v1-test/websites/100/users/test 时,这是否有效? (在这种情况下你希望它分叉吗?)
    【解决方案2】:

    问题在于 match_type 的定义真的......很奇怪:

    $match_types = array(
                'i' => '[0-9]++',
                'a' => '[0-9A-Za-z]++',
    [...]
    

    因此,您不能真正捕获对应于 [a-zA-Z] 的序列...我看到的唯一选择是使用 3 条路线:

    $route1: '/websites/[i:websiteId]/users/[i:id]?'
    $route2: '/websites/[i:websiteId]/users/[a:filename]'
    $route3: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]'
    

    并为路线 2 和 3 分配相同的操作。然后你会得到这个:

    • /api/v1-test/websites/100/users/ 匹配 1
    • /api/v1-test/websites/100/users/4 匹配 1
    • /api/v1-test/websites/100/users/test 被 2 匹配
    • /api/v1-test/websites/100/users/test.csv 被 3 匹配

    这似乎是您想要的行为。

    另一个(更简单的)解决方案是利用以下文档:

    路由自动匹配整个请求 URI。
    如果只需要匹配请求URI的一部分
    或使用自定义正则表达式,使用 @ 运算符。

    然后您可以像这样定义您的路线:

    $route1: '@/websites/[0-9]+/users/[0-9]*$'
    $route1: '@/websites/[0-9]+/users/[a-zA-Z]+(\.[a-zA-Z]+)?$'
    

    【讨论】:

    • 从哲学上讲,我更喜欢这个答案。我认为使用多条路线有潜力。但我仍然需要 ?因为后面的所有参数。所以我不清楚您的更改如何阻止 user/4 匹配路由 3。
    • 所以我错了。 PHP 理解 ?在 URL 中,无需我将其添加到路由中。
    • @BradWhite:实际上,当我再次阅读我的答案时,我认为第一个解决方案毕竟行不通... user/4 与路由 3 不匹配,因为它需要扩展在文件名之后。但是我认为 user/4 仍然会匹配路由 1 和 2。但是,我很确定第二种解决方案正是您正在寻找的。​​span>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 2021-03-14
    • 2015-05-25
    • 1970-01-01
    • 2013-05-05
    • 2016-12-15
    • 2012-03-12
    相关资源
    最近更新 更多