使用正则表达式匹配复杂的路由


Matching a complicated route with a regular expression

我目前正在为一个基于PHP的大型网站制作请求路由器,但是我在尝试为我的路由使用自定义的表达形式时遇到了困难。

虽然我知道有预先制作的替代品和路由器可以让我的生活更轻松,并且具有相同的功能(事实上,我一直在查看它们的源代码以尝试解决这个问题),但我仍然是一个编程学生,学习如何创建自己的路由器只能是一件好事!


例子:

下面是我的一个route表达式的例子:

  • <protocol (https?)>://<wildcard>.example.com/<controller>/{<lang=en (en|de|pl)>/}<name ([a-zA-Z0-9_-]{8})>

这可以很好地匹配以下任何一个:

  • http://www.example.com/test/en/hello_123
  • https://subdomain.example.com/another_test/hello_45

返回给我一个漂亮的,方便的数组,像这样(对于后者):

array(
    'protocol' => 'http',
    'wildcard' => 'subdomain',
    'controller' => 'another_test',
    'lang' => 'en',
    'name' => "hello_45"
)

我还可以首先包含一个数组,其默认值将被路由器找到的值覆盖。因此,例如,我可以省略<controller>变量,而只写test,然后使用数组,添加"controller"=>"test"


规则如下:

  • 没有匹配,就没有匹配。变量必须存在,如果不存在,则跳过该路由。再见。幸运的是,可选部分不必存在。
  • <>之间的任何内容都是变量。转义的'<'>被忽略,即使在。URL中匹配的区域保存到结果数组中,变量名作为关键字。
  • 花括号{}将部分标记为可选的,并且永远不能在变量<>。它们之间的任何内容都可以在目标中忽略—但是,如果为中间的任何变量指定了默认值,则必须将该变量添加到结果数组中,使用名称作为键,并使用默认值作为值。转义大括号将被忽略。
  • 变量不必有默认值,但是如果你添加一个,它需要在=之后,如<name=default>
  • 可以添加
  • Regex规则,在名称或默认值之后用空格分隔,并将其括在括号()中。转义括号当然会被忽略。
  • 最后,你可以把正则表达式规则,在括号里,任何地方,如果你不介意匹配任何东西,没有得到结果。所以,我可以用(['/]+)代替<controller>,但是我必须使用数组来为它设置一个值。

我试过了:

我一直在阅读我能找到的每个路由器的源代码。

到目前为止,我已经完成了几个讨厌的小正则表达式,但是我意识到我完全困惑于如何组合它们并扩展它们。

  • 匹配括号,忽略转义的部分:{([^{'']*(?:''.[^}'']*)*)}

  • 匹配一个变量,有或没有默认值:<([^<'']*(?:''.[^>'']*)*)(?:=?([^<>'']*))>

  • 这是一种邪恶的地狱,就像我写了这篇文章:<([^<'']*(?:''.[^>'']*)*)(?:=?([^<>'']*))(?: ?)('([^{}<>'(')'']+'))?>(但是,它确实匹配变量和Regex部分。)


有没有人能给我一些提示,甚至是提供类似功能的库的示例源代码?如果这真的是几乎不可能自己编码,有没有一个足够好的库可以使用?

如果您试图匹配域,这个regex101演示应该将这些部分与命名为。

的各个部分匹配。

另一方面,如果您试图匹配路由表达式,那么这个regex101演示可以解析到目前为止指定的令牌。

我可能错过了一些规范,但您可以随时留下反馈并解释它的不足之处(甚至可以更新该站点本身的正则表达式并保存新版本)。