查找包含增加的 1 的子串

Find a substring that contains increased 1s

我有一个仅由 01 组成的字符串,我需要找到一个以 1 开头并以另一个 [= 级联结束的子字符串12=]秒,每匹配1次,连续1次加一。

例如,0101101011101会捕捉到1011010111 .

我试过了

(?:(1(?(1))).*?)+

但是it doesn't work.

输入 输出
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)

https://regex101.com/r/dam2qA/1/

您也可以使用(感谢 JvdV

^0*\K(?:[01]*?((?(1))1))+
  • ^ 字符串开头
  • 0* 匹配可选零
  • \K清理当前匹配缓冲区
  • (?:非捕获组整体重复
    • [01]*?尽可能匹配可选的01
    • ( 捕获 组 1
      • (?(1))1 if子句,如果where是第1组,匹配我们已有的,加一个1
    • ) 关闭组 1
  • )+关闭非捕获组并重复1+次

Regex demo | Php demo

$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