【问题标题】:Find a substring that contains increased 1s查找包含增加的 1 的子字符串
【发布时间】:2021-08-21 07:02:44
【问题描述】:

我有一个仅由01组成的字符串,我需要找到一个以1开头,并以1s的另一个级联结尾的子字符串,每个匹配@987654327 @连续的1加一。

例如,0101101011101 会捕获 1011010111

我试过了

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

但是it doesn't work.

input groups output
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 并逐组计数。
  • 你需要只使用正则表达式吗?
  • @TimBiegeleisen 最好是正则表达式,但不是必须的。我正在使用 PHP7.3 顺便说一句

标签: php regex pcre


【解决方案1】:

这应该可行:

^.*?\K(?:((?(1)\1)1).*?)*(?1)

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

【讨论】:

  • 很好,你能补充一些关于为什么这样有效的详细解释吗?
  • ^0*\K(?:(1(?(1)\1)).*?)*(?1) 可能会更高效一些
【解决方案2】:

您也可以使用(感谢JvdV

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

Regex demo | Php demo

$strings = [
    "01",
    "1001111",
    "010011111",
    "0100111110001110",
    "0100111011001110",
    "0100111110011110",
    "0100111111111111110001110",
    "0100111011001110",
    "1011010111",
    "0100111011001110",
];

$pattern = '/^0*\K(?:[01]*?((?(1)\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

【讨论】:

  • 谢谢,但它似乎失败了0100111011001110,它给了我10011 而不是10011101100111:/
  • 啊,我看到示例字符串1011010111 我认为它应该每一步递增,让我尝试更新它。
  • @JvdV 是的,我认为你可以点那个,所以最后一个 1 的范围应该等于或大于已经最大的 ^0*\K(?:[01]*?((?(1)\1)1))+regex101.com/r/3PWwag/1
  • 这很聪明,hiroshi 的回答也很有效,但是 ++kodus 进行详细解释
  • 这真是个很棒的正则表达式
【解决方案3】:

这使用了正则表达式和循环的组合。正则表达式只查找当前预期的 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多