查找包含增加的 1 的子串
Find a substring that contains increased 1s
我有一个仅由 0
和 1
组成的字符串,我需要找到一个以 1
开头并以另一个 [= 级联结束的子字符串12=]秒,每匹配1
次,连续1
次加一。
例如,0101101011101
会捕捉到1011010111 .
我试过了
(?:(1(?(1))).*?)+
输入
组
输出
01
0[(1)]
1
1001111
[(1)00(11)]11
10011
010011111
0[(1)00(11)(111)]
10011111
0100111110001110
0[(1)00(11)(111)]0001110
10011111
0100111011001110
0[(1)00(11)101100(111)]0
10011101100111
0100111110011110
0[(1)00(11)(111)00(1111)]0
10011111001111
这结合了正则表达式和循环。正则表达式只查找当前期望的 1 的数量并捕获第一个的位置(使用 PREG_OFFSET_CAPTURE
)。这使用计数器并使用 /([1]{".$i.",".$i."})/
构建正则表达式。所以这看起来像 /([1]{1,1})/
等
然后在循环中,它增加预期的 1 的数量,并从最后一个的位置开始下一次搜索(偏移找到的 1 的数量)。
$results = [];
$offset = 0;
$i = 1;
while ( preg_match("/([1]{".$i.",".$i."})/", $test, $matches,
PREG_OFFSET_CAPTURE, $offset )) {
$offset = $matches[1][1] + $i;
$results[] = $matches[1];
$i++;
}
print_r($results);
这应该有效:
^.*?\K(?:((?(1))1).*?)*(?1)
您也可以使用(感谢 JvdV)
^0*\K(?:[01]*?((?(1))1))+
^
字符串开头
0*
匹配可选零
\K
清理当前匹配缓冲区
(?:
非捕获组整体重复
[01]*?
尽可能匹配可选的0
或1
(
捕获 组 1
(?(1))1
if子句,如果where是第1组,匹配我们已有的,加一个1
)
关闭组 1
)+
关闭非捕获组并重复1+次
$strings = [
"01",
"1001111",
"010011111",
"0100111110001110",
"0100111011001110",
"0100111110011110",
"0100111111111111110001110",
"0100111011001110",
"1011010111",
"0100111011001110",
];
$pattern = '/^0*\K(?:[01]*?((?(1))1))+/m';
foreach ($strings as $s) {
if (preg_match($pattern, $s, $match)) {
echo "$s --> " . $match[0] . PHP_EOL;
}
}
输出
01 --> 1
1001111 --> 10011
010011111 --> 10011111
0100111110001110 --> 10011111
0100111011001110 --> 10011101100111
0100111110011110 --> 10011111001111
0100111111111111110001110 --> 10011111111111111
0100111011001110 --> 10011101100111
1011010111 --> 1011010111
0100111011001110 --> 10011101100111
我有一个仅由 0
和 1
组成的字符串,我需要找到一个以 1
开头并以另一个 [= 级联结束的子字符串12=]秒,每匹配1
次,连续1
次加一。
例如,0101101011101
会捕捉到1011010111 .
我试过了
(?:(1(?(1))).*?)+
输入 | 组 | 输出 |
---|---|---|
01 |
0[(1)] |
1 |
1001111 |
[(1)00(11)]11 |
10011 |
010011111 |
0[(1)00(11)(111)] |
10011111 |
0100111110001110 |
0[(1)00(11)(111)]0001110 |
10011111 |
0100111011001110 |
0[(1)00(11)101100(111)]0 |
10011101100111 |
0100111110011110 |
0[(1)00(11)(111)00(1111)]0 |
10011111001111 |
这结合了正则表达式和循环。正则表达式只查找当前期望的 1 的数量并捕获第一个的位置(使用 PREG_OFFSET_CAPTURE
)。这使用计数器并使用 /([1]{".$i.",".$i."})/
构建正则表达式。所以这看起来像 /([1]{1,1})/
等
然后在循环中,它增加预期的 1 的数量,并从最后一个的位置开始下一次搜索(偏移找到的 1 的数量)。
$results = [];
$offset = 0;
$i = 1;
while ( preg_match("/([1]{".$i.",".$i."})/", $test, $matches,
PREG_OFFSET_CAPTURE, $offset )) {
$offset = $matches[1][1] + $i;
$results[] = $matches[1];
$i++;
}
print_r($results);
这应该有效:
^.*?\K(?:((?(1))1).*?)*(?1)
您也可以使用(感谢 JvdV)
^0*\K(?:[01]*?((?(1))1))+
^
字符串开头0*
匹配可选零\K
清理当前匹配缓冲区(?:
非捕获组整体重复[01]*?
尽可能匹配可选的0
或1
(
捕获 组 1(?(1))1
if子句,如果where是第1组,匹配我们已有的,加一个1
)
关闭组 1
)+
关闭非捕获组并重复1+次
$strings = [
"01",
"1001111",
"010011111",
"0100111110001110",
"0100111011001110",
"0100111110011110",
"0100111111111111110001110",
"0100111011001110",
"1011010111",
"0100111011001110",
];
$pattern = '/^0*\K(?:[01]*?((?(1))1))+/m';
foreach ($strings as $s) {
if (preg_match($pattern, $s, $match)) {
echo "$s --> " . $match[0] . PHP_EOL;
}
}
输出
01 --> 1
1001111 --> 10011
010011111 --> 10011111
0100111110001110 --> 10011111
0100111011001110 --> 10011101100111
0100111110011110 --> 10011111001111
0100111111111111110001110 --> 10011111111111111
0100111011001110 --> 10011101100111
1011010111 --> 1011010111
0100111011001110 --> 10011101100111