用于URL路由的正则表达式 - 匹配除此列表中的单词之外的字母数字和短划线

Zak*_*ziz 2 regex codeigniter url-routing regex-negation

我正在使用CodeIgniter编写一个应用程序,允许用户注册一个帐户,并为其分配一个他们选择的URL(URL slug)(例如domain.com/user-name).CodeIgniter具有URL路由功能,允许使用正则表达式(链接).

用户只能注册包含字母数字字符,破折号( - )和分数(_)的URL.这是我用来验证URL slug有效性的正则表达式:^[A-Za-z0-9][A-Za-z0-9_-]{2,254}$

我正在使用网址路由功能将一些网址路由到我网站上的功能(例如/home -> /pages/index,/activity -> /user/activity),因此这些特定网址显然无法由用户注册.

我对正则表达式缺乏经验,但试图编写一个表达式,可以匹配任何带有字母数字/短划线/下划线的URL slugs,除非它们是以下任何一种:

  1. default_controller
  2. 404_override
  3. 活动

这是我用来尝试匹配具有该特定条件的单词的代码:

$route['(?!default_controller|404_override|home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';
Run Code Online (Sandbox Code Playgroud)

但它没有正确路由.有人可以帮忙吗?(附带问题:在尝试与URL匹配时,是否有必要使用^$在正则表达式中?)

Ake*_*rts 7

好吧,让我们分开吧.

忽略CodeIgniter的保留路由.

default_controller404_override路线的部分是不必要的.将路由与请求的URI进行比较,以查看是否存在匹配.这两个项目极不可能在您的URI中,因为它们是CodeIgniter的特殊保留路由.所以让我们忘记它们吧.

$route['(?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';
Run Code Online (Sandbox Code Playgroud)

抓住一切!

使用正则表达式,使用括号创建组().然后可以使用后向引用检索该组 - 在我们的示例中,$1, $2, etc.位于路径的第二部分中.您尝试排除的第一组项目周围只有一个组,因此无法正确捕获整个外卡.你已经发现了这一点,并在整个项目周围添加了一组(好!).

$route['((?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';
Run Code Online (Sandbox Code Playgroud)

展望?!

在这个主题home|activity上,由于?!在开始时的使用,第一组实际上并不是传统的组.这被称为负向前瞻,它是一个复杂的正则表达式功能.它使用不正确:

如果你想要匹配其他东西不匹配的东西,那么否定的先行是必不可少的.

我可以用更多的东西来解决这个问题,但基本上我们并不是真的想要或者首先需要它,所以如果你愿意,我会让你探索.

为了让您的生活更轻松,我建议将路线中的家庭,活动和其他现有控制器分开.CodeIgniter将从上到下查看路由列表,一旦匹配,它就会停止检查.因此,如果您在通配符之前指定现有控制器,它们将匹配,并且可以大大简化您的通配符正则表达式.

$route['home'] = 'pages';
$route['activity'] = 'user/activity';
$route['([A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';
Run Code Online (Sandbox Code Playgroud)

请记住按照从最具体到最少的顺序列出您的路线.外卡匹配不如完全匹配(如家庭和活动)那么具体,因此它们应该在(下面)之后.

现在,这是所有复杂的东西.再多一点.

请记住,破折号-[]括号之间具有特殊含义.如果要匹配文字短划线,则应该转义它们.

$route['([A-Za-z0-9][A-Za-z0-9_\-]{2,254})'] = 'view/slug/$1';
Run Code Online (Sandbox Code Playgroud)

请注意,您的字符重复最小值/最大值{2,254}仅适用于第二组字符,因此您的用户名最少为3个字符,最多为255个.如果您没有意识到这一点,那就是一个FYI.

我看到了你自己对这个问题的回答,这只是丑陋的.抱歉.该^$符号在整个预读(仍然不应该出现在第一位)使用不当.对于您正在测试它的一些用例,它可能"起作用",但它将在未来给您带来问题和麻烦.

希望现在您能更多地了解正则表达式以及它们在路由过程中的匹配方式.

并回答你的问题,不,你不应该使用^$你的正则表达式的开头和结尾 - CodeIgniter将为你添加.


使用404,卢克......

此时,您的路线已得到改善,应该可以正常使用.不过,我会把它扔出去,你可能要考虑使用定义为404_override处理你的外卡的控制器/方法.这样做的主要好处是,您不需要任何路由来指示外卡,也不需要防止外卡使用现有控制器.你只需要:

$route['404_override'] = 'view/slug';
Run Code Online (Sandbox Code Playgroud)

然后,你的View :: slug()方法将检查URI,看看它是否是一个有效的模式,然后检查它是否作为用户存在(毫无疑问,与你的slug方法相同).如果确实如此,那么你很高兴.如果没有,则抛出404错误.

它似乎并不优雅,但效果很好.如果它听起来更好,请试一试.