【问题标题】:Regex quantified capture正则表达式量化捕获
【发布时间】:2012-03-31 00:31:45
【问题描述】:
php > preg_match("@/m(/[^/]+)+/t/?@", "/m/part/other-part/t", $m);
php > var_dump($m);
array(2) {
  [0]=>
  string(20) "/m/part/other-part/t"
  [1]=>
  string(11) "/other-part"
}
php > preg_match_all("@/m(/[^/]+)+/t/?@", "/m/part/other-part/t", $m);
php > var_dump($m);
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(20) "/m/part/other-part/t"
  }
  [1]=>
  array(1) {
    [0]=>
    string(11) "/other-part"
  }
}

在上述示例中,我希望捕获同时匹配 /part/other-part,不幸的是,正则表达式 /m(/[^/]+)+/t/? 不能像我预期的那样捕获两者。

此捕获不应仅与此样本匹配,它应捕获捕获组的未定义重复次数;例如/m/part/other-part/and-another/more/t

更新: 鉴于这是预期的行为,我的问题是如何实现我的匹配?

【问题讨论】:

  • 我希望捕获组由于量词+而被重复应用
  • 另外,“不起作用”在问题标题中也不好。事实上,量词确实像 PCRE 中宣布的那样工作。
  • @hakre 从标题中删除了不起作用的部分。根据您的回答,我的记忆似乎在欺骗我,因为我记得对捕获组进行了量化。
  • 仔细看,我假设您想要捕获子组匹配,这是 PHP 不支持的,这是一个 javascript 示例:Can you retrieve multiple regex matches in JavaScript?

标签: php regex


【解决方案1】:

正如评论中已经写的那样,您不能立即执行此操作,因为preg_match 也不允许您返回相同的子组匹配项(就像您可以使用 Javascript 或 .Net 一样,请参阅 @ 987654321@)。因此,您可以将操作分为多个步骤:

  1. 匹配主题,提取您感兴趣的部分。
  2. 只匹配感兴趣的部分。

代码:

$subject = '/m/part/other-part/t';
$subpattern = '/[^/]+';
$pattern = sprintf('~/m(?<path>(?:%s)+)/t/?~', $subpattern);
$r = preg_match($pattern, $subject, $matches);
if (!$r) return;
$r = preg_match_all("~$subpattern~", $matches['path'], $matches);
var_dump($matches);

输出:

array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(5) "/part"
    [1]=>
    string(11) "/other-part"
  }
}

【讨论】:

    【解决方案2】:

    试试这个:

    preg_match_all("@(?:/m)?/([^/]+)(?:/t)?@", "/m/part/other-part/another-part/t", $m);
    var_dump($m);
    

    它给出:

    array(2) {
      [0]=>
      array(3) {
        [0]=>
        string(7) "/m/part"
        [1]=>
        string(11) "/other-part"
        [2]=>
        string(15) "/another-part/t"
      }
      [1]=>
      array(3) {
        [0]=>
        string(4) "part"
        [1]=>
        string(10) "other-part"
        [2]=>
        string(12) "another-part"
      }
    }
    

    //编辑

    IMO 做你想做的最好的方法是使用来自 @stema 的 preg_match() 并通过 / 分解结果以获得你想要的零件列表。

    【讨论】:

    • /m 开头可选?我明白你为什么要这样做,但这不是不准确吗?
    • 是的,它不精确,但如果它不是可选的,那么正则表达式无法分解他想要的部分。我会使用简单的preg_match() + explode() 来获得他想要的零件。
    • @piotrekkr 你的回答更符合这个问题(我会接受它);但我将使用stema的响应而不是我将执行 preg_match() 并爆炸,而不是为此严格检查字符串是否以 (/m) 开头并以 (/t/?) 结尾:)跨度>
    【解决方案3】:

    这就是捕获组的工作方式。重复捕获组仅在正则表达式完成后存储最后一个匹配项。那在你的测试“/other-part”中。

    试试这个

    /m((?:/[^/]+)+)/t/?
    

    here on Regexr,鼠标悬停在比赛上,可以看到捕获组的内容。

    只需在开头添加?: 并在整个重复部分周围添加另一个即可让您的小组不被捕获。

    在php中

    preg_match_all("@/m((?:/[^/]+)+)/t/?@", "/m/part/other-part/t", $m);
    var_dump($m);
    

    输出:

    array(2) { 
        [0]=> array(1) { 
            [0]=> 
            string(20) "/m/part/other-part/t" 
        }
        [1]=> array(1) { 
            [0]=> 
            string(16) "/part/other-part" 
        }
    }
    

    【讨论】:

    • 请查看我更新的问题。因为如果是这样,我仍然想知道如何实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 2018-03-11
    相关资源
    最近更新 更多