尝试学习为PHP编写RegExp

尝试学习为PHP编写RegExp,php,regex,datetime,Php,Regex,Datetime,我试图学习如何编写正则表达式,但似乎我所有的搜索都会导致不清楚的信息。所以我的问题有两个方面 有没有人知道新手如何学习编写正则表达式 如何编写将字符串1y 311d 16h 42m分解为变量的正则表达式 我希望将上面的文本字符串分解为如下内容: $duration[years] = 1; $duration[days] = 311; $duration[hours] = 16; $duration[minutes] = 42; 请注意,总数字可能并不总是相同的,例如,可能是两位数的天数。差不多

我试图学习如何编写正则表达式,但似乎我所有的搜索都会导致不清楚的信息。所以我的问题有两个方面

  • 有没有人知道新手如何学习编写正则表达式
  • 如何编写将字符串1y 311d 16h 42m分解为变量的正则表达式
  • 我希望将上面的文本字符串分解为如下内容:

    $duration[years] = 1;
    $duration[days] = 311;
    $duration[hours] = 16;
    $duration[minutes] = 42;
    
    请注意,总数字可能并不总是相同的,例如,可能是两位数的天数。差不多。25d或一些可以省略。我可能只有几天和几个小时。最后,顺序可能会改变。也许是写了几天,然后是几年等等

    我知道我可以用explode函数和strpos很容易地做到这一点,但我真的很想学习Regex,所以我把它作为一个例子,因为我知道它们对于这样的事情非常强大

    1)一些有用的页面:

    2) 具体而言,这:

    $pattern = '/(?:(?P<years>\d+)y\s*)?(?:(?P<days>\d+)d\s*)?(?:(?P<hours>\d+)h\s*)?(?:(?P<minutes>\d+)m\s*)?/';
    preg_match($pattern, '1y 311d 16h 42m', $duration);
    print_r($duration);
    // Array
    // (
    //     [0] => 1y 311d 16h 42m
    //     [years] => 1
    //     [1] => 1
    //     [days] => 311
    //     [2] => 311
    //     [hours] => 16
    //     [3] => 16
    //     [minutes] => 42
    //     [4] => 42
    // )
    preg_match($pattern, '311d 42m', $duration);
    print_r($duration);
    // Array
    // (
    //     [0] => 1y 311d 16h 42m
    //     [years] =>
    //     [1] =>
    //     [days] => 311
    //     [2] => 311
    //     [hours] =>
    //     [3] =>
    //     [minutes] => 42
    //     [4] => 42
    // )
    
    $pattern='/(?:(?P\d+)y\s*)(?:(?P\d+)d\s*)(?:(?P\d+)h\s*)(?:(?P\d+)m\s*))/;
    预赛($1Y311D 16H42M模式,$duration);
    打印(持续时间);
    //排列
    // (
    //[0]=>1y 311d 16h 42m
    //[年]=>1
    //     [1] => 1
    //[天]=>311
    //     [2] => 311
    //[小时]=>16
    //     [3] => 16
    //[分钟]=>42分钟
    //     [4] => 42
    // )
    赛前比赛($模式,'311d 42m',$持续时间);
    打印(持续时间);
    //排列
    // (
    //[0]=>1y 311d 16h 42m
    //[年]=>
    //     [1] =>
    //[天]=>311
    //     [2] => 311
    //[小时]=>
    //     [3] =>
    //[分钟]=>42分钟
    //     [4] => 42
    // )
    
    但这将给出固定的顺序。如果订单可以更改,则regexp不是一个好工具。在这种情况下仍然有可能,但相当尴尬。这是:

    $pattern = "/(?=.*?(?:(?P<years>\d+)y|$))(?=.*?(?:(?P<days>\d+)d|$))(?=.*?(?:(?P<hours>\d+)h|$))(?=.*?(?:(?P<minutes>\d+)m|$))/";    
    preg_match($pattern, '311d 16h 1y', $duration);
    print_r($duration);
    // Array
    // (
    //     [0] =>
    //     [years] => 1
    //     [1] => 1
    //     [days] => 311
    //     [2] => 311
    //     [hours] => 16
    //     [3] => 16
    // )
    
    $pattern=“/(?=*)(?:(?P\d+)y |$)(?=*(?:(?P\d+)d |$)(?=*(?:(?P\d+)h |$)(?=*(?P\d+)m |$)/”;
    预匹配($311d 16h 1y'模式,$duration);
    打印(持续时间);
    //排列
    // (
    //     [0] =>
    //[年]=>1
    //     [1] => 1
    //[天]=>311
    //     [2] => 311
    //[小时]=>16
    //     [3] => 16
    // )
    

    在regex101中输入这些模式(不带前导和尾随斜杠)将为您解释它试图匹配的内容。从中查找其他示例并输入它们,然后尝试查看它们是如何工作的。经验是最好的老师。

    那么您可以直接将数组键放入正则表达式?是什么让它添加带有索引号的额外键?命名的捕获组是一个扩展。通常,捕获组是数字的;PHP的
    (?P..
    将创建传统的数字捕获和命名捕获。
    0
    组不同:它返回整个匹配的子字符串;但是,由于在上一个示例中,所有操作都是由lookaheads完成的,它们是空宽度断言,因此匹配的子字符串也是宽度0。