我正在尝试匹配以下模式并创建如下所述的数组:
letter 'c' followed by digit
letter 'c' followed by digit dash digit
digit may be followed by an other digit enclosed in square parentheses []
模式用逗号分隔。
示例:
c2,c3-5,c6[2],c8[4]-10,c14-21[5]
这些数字是对法律条款段落的引用,其中有破折号意味着这是一系列段落。
例如:
c3-5 = paragraphs from 3 to 5
使用以下正则表达式,我可以匹配和分离数字:
('d+('['d+'])?-'d+('['d+'])?)|('d+('['d+'])?)
https://regex101.com/r/iQ2pQ3/1
但为了有效地使用这些数字,我试图构建一个具有以下结构的阵列,但没有成功:
Array
(
[0] => Array
(
[start] => 2
[end]=>
)
[1] => Array
(
[start] => 3
[end] => 5
)
[2] => Array
(
[start] => 6[2]
[end] =>
)
[3] => Array
(
[start] => 8[4]
[end] => 10
)
[4] => Array
(
[start] => 14
[end] => 21[5]
)
)
您可以看到,单个匹配项是用关键字[start]
添加到数组中的,当有短划线(范围)时,第一个数字用关键字[start]
添加,第二个数字用密钥[end]
添加。
我认为唯一的方法是通过逗号首先explode
字符串,然后在单个分解的字符串上使用正则表达式。即使是思想也不知道如何构建如上所述的数组。
有更好(更紧凑、更优雅)的方法吗?
使用以下基于正则表达式的解决方案(请参阅演示):
$re = '~c(?<start>'d+(?:'['d+])?)(?:-(?<end>(?&start)?))?~';
$str = "c2,c3-5,c6[2],c8[4]-10,c14-21[5]";
preg_match_all($re, $str, $matches);
$res = array_map(function($ms, $me) {
return array("start" => $ms, "end" => $me);
}, $matches["start"], $matches["end"]);
print_r($res);
regex与anubhava的类似,但我在命名子例程调用的帮助下缩短了它(它实际上递归、重显start
子模式):
c(?<start>'d+(?:'['d+])?)(?:-(?<end>(?&start)?))?
请参阅regex演示,下面是它的解释:
c
-文字c
(?<start>'d+(?:'['d+])?)
-(名为"start"的组)一个强制性子模式,'d+
匹配1个以上数字,可选后接1个:
,后接[
+数字+]
(?:-(?<end>(?&start)?))?
--
的1或0(可选)序列,后跟"开始"组(该值放入"结束"组)
您可以将正则表达式修改为这样,以捕获空匹配:
c(?P<start>'d+(?:'['d+'])?)-?(?P<end>'d+(?:'['d+'])?|)(?=,|$)
RegEx演示
(?P<end>'d+(?:'['d+'])?|)
确保我们也捕获end
组中的空匹配。