3

我正在用 PHP 为基于 MVC 的站点重新编写路由处理类,并且需要一个正则表达式来检测 URL 中的分页字符串。分页字符串由三个不同的部分组成;

  • 页码检测: /page/[NUMERIC]/
  • 每页项目检测: /per_page/[NUMERIC]/
  • 订货检测: /sort/[ALMOST_ANY_CHARACTER]/[asc or desc]/

由于之前的开发方式,这三个部分可以按任何顺序排列。我需要继续使用许多现有链接以及用于处理分页的代码(还没有重新编写的计划)-因此不可能更改分页代码以始终生成一致的 url。

因此,我需要构建一个正则表达式模式来检测分页结构的每一种可能组合。我有三种模式来检测每个部分,如下所示:

  • 页码检测: (page/\d+)
  • 每页项目检测: (per_page/\d+)
  • 订货检测: (sort/([a-zA-Z0-9\.\-_%=]+)/(asc|desc))

作为编写复杂的新手(无论如何这对我来说很复杂!)正则表达式模式,我唯一能想到的就是两个结合我对每个 url 结构的三种模式(例如 /pagenum/ordering/perpage/, /pagenum/perpage/ordering/) 并使用 | 运算符作为“或”语句。

有没有更好/更有效的方法来做到这一点?

我正在使用preg_match.

4

3 回答 3

4

您可以使用前瞻。在前瞻完全匹配后,正则表达式引擎的位置跳回到它开始的位置(这就是为什么它被称为 * look *ahead;它实际上并不推进主题字符串中的位置或在匹配中包含任何内容)。由于您不知道所需的部分何时出现,因此从字符串的开头开始所有三个前瞻,并在捕获组之前添加.*以允许任意位置:

^(?=.*(page/\d+))(?=.*(per_page/\d+))(?=.*(sort/([a-zA-Z0-9\.\-_%=]+)/(asc|desc)))

您甚至可以稍微切换捕获组:

preg_match(
  '~^(?=.*page/(\d+))(?=.*per_page/(\d+))(?=.*sort/([a-zA-Z0-9\.\-_%=]+)/(asc|desc))~', 
  $input,
  $match
);

现在捕获将是:

$match[1] => page number
$match[2] => items per page
$match[3] => sort key
$match[4] => sort order

如果其中任何一个可以是可选的,您可以简单地使用?.

于 2012-12-15T18:51:45.097 回答
1

可以使用前瞻,但除非我遗漏了什么,否则我认为这里没有必要——您可能只使用 OR 运算符:

(/(page/\d+)|/(per_page/\d+)|/(sort/([a-zA-Z0-9\.\-_%=]+)/(asc|desc)))+

此处的外部组搜索任何组 1 OR 组 2 或组 3 的 1 个或多个实例。

更多 URL 路由提示:

这种通用方法实际上也可以让您简化一些事情。与其在 Regex 中为您的路线定义所有规则,不如先检查某些类型的操作,然后在代码中处理它们。最简单的版本:

(/(page|per_page)/([\d+]))+

现在(对于每个外部组匹配)您将获得一个包含“动作”和“值”的匹配列表。打开动作,相应地处理值。

要按照您指定的方式处理排序(两个值参数而不是一个),我们将添加另一层.. 并使其更有趣,假设您决定添加第四个操作search,它搜索特定的一些内容的字段:

(/(page|per_page)/([\d+])|/(sort|search)/([^/]+)/([^/]+))+

同样,在评估您的匹配列表时,首先检查操作 - 根据它是哪个操作,您将知道要处理多少个连续匹配值。

希望这会有所帮助。

于 2012-12-15T19:04:29.643 回答
0

不要使用正则表达式。仅仅因为您在字符串上进行操作并不意味着正则表达式就是要走的路。

将您的路径拆分/为一个数组,然后将路径的每个部分作为数组的单个元素处理。

$parts = explode( '/', $path );

if ( ( $parts[0] == 'page' ) && is_integer( $parts[1] ) ) {
....
于 2012-12-15T19:26:28.690 回答