【问题标题】:PHP: Best way to "explode" string based on regex / find elements between regex machesPHP:基于正则表达式“爆炸”字符串的最佳方法/在正则表达式匹配之间查找元素
【发布时间】:2022-01-25 18:39:16
【问题描述】:

假设我有一个字符串,例如:

155+44x3/2-12

我怎样才能将其拆分,以便最终结果是:

$numbers = [155, 44, 3, 2, 12];
$operators = ['+', 'x', '/', '-'];

我可以很容易地使用正则表达式分别获得一个或另一个,但是有没有一种好方法可以使用正则表达式获取数字,然后将“其余部分”放入另一个变量而无需为其编写显式正则表达式?数组项应按照初始字符串正确排序。

或者在这种情况下最好使用两个单独的正则表达式子句?例如

preg_match_all($string, "/(\d+)/", $numbers);
preg_match_all($string, "/(\D+)/", $rest);

【问题讨论】:

  • 你说的是preg_match_all("/\d+|\D+/", $string, $numbers);吗?或者你的意思是你想得到两个单独的数组?
  • 我想获得两个数组,包含正确索引的项目,但理想情况下使用单个操作/正则表达式

标签: php regex


【解决方案1】:

您可以在单个 preg_match_all 调用中使用此正则表达式中的 2 个捕获组来执行此操作:

(\d+)(\D*)

匹配捕获组 #1 中的 1+ 个数字并匹配捕获组 #2 中的 0 个或多个非数字

RegEx Demo

$s = '155+44x3/2-12';
if (preg_match_all('/(\d+)(\D*)/', $s, $m)) {
   $numbers = $m[1];
   $operators = array_filter($m[2]);
   // print arrays
   print_r($numbers);
   print_r($operators);
}

输出:

Array
(
    [0] => 155
    [1] => 44
    [2] => 3
    [3] => 2
    [4] => 12
)
Array
(
    [0] => +
    [1] => x
    [2] => /
    [3] => -
)

array_filter 已用于过滤掉数组中的空元素。

【讨论】:

    【解决方案2】:

    可以肯定的是,使用两个正则表达式并没有错,另一个答案的preg_match_all() 也可以。另一种方法是将它们捕获到单个数组中,然后将其分成两个。由于我们正在讨论拆分,让我们使用 preg_split()PREG_SPLIT_DELIM_CAPTURE 标志。这会产生一个数字数组,如下所示为您的示例方程:

    Array [
      [0] => 155
      [1] => +
      [2] => 44
      [3] => x
      [4] => 3
      [5] => /
      [6] => 2
      [7] => -
      [8] => 12
    ]
    

    现在,由于您的等式将以数字开头,因此可以相当安全地假设您的所有运算符在结果数组中都有奇数键。然后,我们可以在键上用% 2 == 0 或零模数将它们分开,从而将奇数和偶数分叉到单独的数组中。

    $equation = '155+44x3/2-12';
    
    // Use ~\s*(\D)\s*~ if you may have spaces around operators
    // Use ~(?<!\D)(\D)~ with lookbehind if you have negative integers
    
    $splits = preg_split('~(\D)~', $equation, -1, PREG_SPLIT_DELIM_CAPTURE);
    
    $bits = [];
    
    array_walk($splits, function($v, $k) use (&$bits) {
        $type = $k % 2 == 0 ? 'numbers' : 'operators';
        $bits[$type][] = $v;
    });
    

    这会导致:

    array(2) {
        ["numbers"] · array(5) {
            [0] · string(3) "155"
            [1] · string(2) "44"
            [2] · string(1) "3"
            [3] · string(1) "2"
            [4] · string(2) "12"
        }
        ["operators"] · array(4) {
            [0] · string(1) "+"
            [1] · string(1) "x"
            [2] · string(1) "/"
            [3] · string(1) "-"
        }
    }
    

    请注意,如果您有- 有符号整数,则将数字与运算符分开的基本正则表达式将失败。您可以添加一个否定的look-behind,排除运算符前面的减号;然后你的正则表达式看起来像~(?&lt;!\D)(\D)~

    运算符周围可能还有空格。在这种情况下,请在运算符捕获/拆分匹配器正则表达式之外添加可选空格:~\s*(\D)\s*~,以便在捕获运算符本身时在拆分中丢弃空格。

    注意您不能将- 有符号数字的负向回溯与 可选 空格结合使用,因为负向回溯需要是固定长度的。您要么有空格(?&lt;!\D\s),要么没有(?&lt;!\D)。这将起作用:~\s*(?&lt;!\D\s)(\D)\s*~ for 155 + 44 x 3 / 2 * -12;而这个~\s*(?&lt;!\D)(\D)\s*~ 用于拆分155+44x3/2*-12

    此外,如果您的方程式使用双字符运算符,例如 PHP 的 ** 用于幂,您将需要修改正则表达式以匹配。如果您有( 括号) 和其他符号,那么它又是另一匹马了。不过,这种方法应该适用于基础知识。

    【讨论】:

    • 这是一个非常有趣的方法,感谢您的出色回答和解释,不胜感激!
    • 当然可以。如果您打算进一步工作并实际将数字与需要整数的函数一起使用,您还需要将“数字”中的任何内容转换为(int)。默认情况下,它们是字符串,它们的来源是真实的,如果你在类型严格模式下工作,它们会抛出错误(一个好主意)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 2019-03-16
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多