【问题标题】:How to split a string by repeated characters in PHP?如何通过PHP中的重复字符拆分字符串?
【发布时间】:2016-01-16 18:25:20
【问题描述】:

我正在尝试将二进制字符串拆分为重复字符数组。

例如,使用此函数拆分的 10001101 数组将是:

    $arr[0] = '1';
    $arr[1] = '000';
    $arr[2] = '11';
    $arr[3] = '0';
    $arr[4] = '1';

(我试图让自己清楚,但如果你仍然不明白,我的问题与this 相同,但针对 PHP,而不是 Python)

【问题讨论】:

标签: php string binary


【解决方案1】:

你可以像这样使用preg_split

示例:

$in = "10001101";
$out = preg_split('/(.)(?!\1|$)\K/', $in);

print_r($out);

输出:

Array
(
    [0] => 1
    [1] => 000
    [2] => 11
    [3] => 0
    [4] => 1
)

正则表达式:

  • (.) - 匹配单个字符并捕获它
  • (?!\1|$) - 查看下一个位置并匹配,如果它与我们刚刚找到的位置不同,也不是字符串的结尾。
  • \K - 将匹配的文本保留在整个正则表达式匹配之外,使该匹配为零宽度。

注意:这在 5.6.13 之前的 PHP 版本中不起作用,因为有一个 bug involving bump-along behavior with \K


在早期版本中也可以使用的替代正则表达式是:

$out = preg_split('/(?<=(.))(?!\1|$)/', $in);

这使用了一个lookbehind而不是\K以使匹配为零宽度。

【讨论】:

  • 天啊,我只是太慢了几秒钟。这是我的:$arg="10001101"; preg_match_all("@(\w)\\1*@", $arg, $matches); print_r($matches[0]);
  • @paul : 出了点问题.. 看看最后一个元素Array ( [0] =&gt; 1 [1] =&gt; 000 [2] =&gt; 11 [3] =&gt; 01 )
  • @SeanJohnson 完美运行,谢谢。但是,答案本身不起作用。
【解决方案2】:
<?php
$s = '10001101';
preg_match_all('/((.)\2*)/',$s,$m);
print_r($m[0]);
/*
Array
(
    [0] => 1
    [1] => 000
    [2] => 11
    [3] => 0
    [4] => 1
)
*/
?>

匹配 1 个或多个重复的字符序列。正则表达式将主题字符存储到第二个捕获组((.),存储为$m[1]),而第一个捕获组包含整个重复序列(((.)\2*),存储为$m[0])。使用 preg_match_all,它会在整个字符串上全局执行此操作。这可以应用于 any 字符串,例如'aabbccddee'。如果您只想限制为01,则在第二个捕获组中使用[01] 而不是.

记住$m可能为空,在使用前要先检查结果是否存在,即isset($m[0])

【讨论】:

    【解决方案3】:

    我在想这样的事情。代码id没有测试,我直接写在评论里,可能会有一些错误,大家可以调整一下。

    $chunks = array();
    $index = 0;
    $chunks[$index] = $arr[0];
    for($i = 1; $i < sizeof($arr) - 1; $i++) {
      if( $arr[$i] == $arr[$i-1] ) {
        $chunks[$index] .= $arr[$i];
      } else {
        $index++;
        $chunks[$index] = $arr[$i];
      }
    }
    

    【讨论】:

      【解决方案4】:

      我不会费心在模式中寻找字符串的结尾。

      最简洁的方法是,捕获第一个出现的字符,然后允许捕获的字符重复零次或多次,然后用\K 重新开始全字符串匹配,这样就不会在爆炸中丢失任何字符。

      代码:(Demo)

      var_export(
          preg_split('~(.)\1*\K~', '10001101', 0, PREG_SPLIT_NO_EMPTY)
      );
      

      输出:

      array (
        0 => '1',
        1 => '000',
        2 => '11',
        3 => '0',
        4 => '1',
      )
      

      如果您不关心正则表达式,这里有一种遍历每个字符的方法,将其与前一个字符进行比较,并有条件地将重复的字符连接到引用变量。

      代码:(Demo) ...与第一个 sn-p 结果相同

      $array = [];
      $lastChar = null;
      foreach (str_split('10001101') as $char) {
          if ($char !== $lastChar) {
              unset($ref);
              $array[] = &$ref;
              $ref = $char;
              $lastChar = $char;
          } else {
              $ref .= $char;
          }
      }
      var_export($array);
      

      【讨论】:

      • @R__ 我看到您在我发布答案后一直在线。您是否有机会接受我的回答,以便研究人员更容易找到完善的解决方案?
      猜你喜欢
      • 1970-01-01
      • 2019-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      • 2017-03-21
      相关资源
      最近更新 更多