我尝试匹配以下模式并创建一个数组,如下所述:
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
字符串解析出来,然后在单个爆炸字符串上使用正则表达式。即便想到也不知道如何构建一个阵列,如上所述。
有更好的(更紧凑和优雅)的方式吗?
答案 0 :(得分:1)
使用以下基于正则表达式的解决方案(请参阅demo):
$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);
正则表达式与anubhava类似,但我在命名子例程调用(实际上是递归,重用,start
子模式)的帮助下缩短了它:
c(?<start>\d+(?:\[\d+])?)(?:-(?<end>(?&start)?))?
请参阅regex demo,以下是其解释:
c
- 文字c
(?<start>\d+(?:\[\d+])?)
- (组名为&#34;开始&#34;)强制性子模式,\d+
匹配1位数字,可选地后跟1次出现:
后跟{ {1}} +位+ [
]
- 1或0(可选)序列(?:-(?<end>(?&start)?))?
后跟&#34; start&#34; group(值放入&#34; end&#34;组)。答案 1 :(得分:0)
您可以将正则表达式修改为此以捕获空匹配:
c(?P<start>\d+(?:\[\d+\])?)-?(?P<end>\d+(?:\[\d+\])?|)(?=,|$)
(?P<end>\d+(?:\[\d+\])?|)
确保我们还会在end
组中捕获空匹配。