【问题标题】:Regex to split string into array of numbers and characters using PHP正则表达式使用 PHP 将字符串拆分为数字和字符数组
【发布时间】:2024-04-15 05:45:02
【问题描述】:

我有一个类似于以下模式的算术字符串。

a. 1+2+3
b. 2/1*100
c. 1+2+3/3*100
d. (1*2)/(3*4)*100

需要注意的是
1.字符串永远不会包含空格。
2. 字符串始终是数字、算术符号(+、-、*、/)和字符 '(' 和 ')' 的组合

我正在寻找 PHP 中的正则表达式来根据字符类型拆分字符并形成如下所示的单个字符串字符数组。
(注意:我不能使用 str_split,因为我想要大于 10 的数字不分开。)

一个。 1+2+3
输出 => [
0 => '1'
1 => '+'
2 => '2'
3 => '+'
4 => '3'
]

b. 2/1*100
输出 => [
0 => '2'
1 => '/'
2 => '1'
3 => '*'
4 => '100'
]`

c。 1+2+3/3*100

输出 => [
0 => '1'
1 => '+'
2 => '2'
3 => '+'
4 => '3'
5 => '/'
@987654351 @
7 => '*'
8 => '100'
]`

d。 (1*2)/(3*4)*100

输出 => [
0 => '('
1 => '1'
2 => '*'
3 => '2'
4 => ')'
5 => '/'
@987654362 @
7 => '3'
8 => '*'
9 => '4'
10 => ')'
11 => '*'
12 => '100'
]

非常感谢您。

【问题讨论】:

  • 欢迎来到 *。不幸的是,这既不是教程网站,也不是网络搜索替代品。然而,我们可以帮助解决certain on-topic problems,但首先你的工作是put some efforts 在这个主题上,包括基本的(re)search
  • 试一试并提供代码,我将与您分享一个更简单的方法。
  • 你最好为这样的工作写一个解析器。

标签: php regex preg-match preg-split


【解决方案1】:

使用这个正则表达式:
(?<=[()\/*+-])(?=[0-9()])|(?<=[0-9()])(?=[()\/*+-])

它将匹配数字或括号与运算符或括号之间的每个位置。
(?<=[()\/*+-])(?=[0-9()]) 匹配左侧带有括号或运算符的位置以及右侧的数字或括号
(?<=[0-9()])(?=[()\/*+-])相同,但左右颠倒。

演示here

【讨论】:

  • 谢谢。正则表达式似乎正在工作,但是当我运行以下代码时 - $re = '/(? array:1 [▼ 0 => "" ] 1 => array:1 [▼ 0 => "" ] ] 我希望数组为 (1, +, 2, + , 3).
  • 我是不是跑错了。谢谢,但我以前很少使用正则表达式,无法使用它们。
  • @ChaitraHegde 我想你想使用 preg_split 函数,而不是 preg_match_all。 php.net/manual/fr/function.preg-split.php
  • @ChaitraHegde 顺便看看 ClasG 的回答,比我的简单。但是,您必须添加 PREG_SPLIT_NO_EMPTY 标志才能删除返回数组中的空元素。
  • 谢谢,preg_split 正是我正在寻找的功能以及您提供的正则表达式。
【解决方案2】:

由于您声明表达式是“干净的”,没有空格等,您可以拆分

\b|(?<=\W)(?=\W)

它在所有单词边界上分割非单词字符之间的边界(使用正向环视匹配两个非单词字符之间的位置)。

See an illustration here at regex101

【讨论】:

    【解决方案3】:

    正如我所说,如果你能提供一些你自己做的工作来解决这个问题,我会帮助你。

    但是,如果在使用算术表达式构建一维数组时,您的目标是解析和计算该数组,那么您应该构建一棵树并通过将运算符作为节点来对其进行分层,分支是操作数:

    '(1*2)/(3*4)*100'
    
    Array
    (
        [operand] => '*',
        [left] => Array
            (
                [operand] => '/',
                [left] => Array
                    (
                        [operand] => '*',
                        [left] => 1,
                        [right] => 2
                    ),
                [right] => Array
                    (
                        [operand] => '*',
                        [left] => 3,
                        [right] => 4
                    )
            ),
        [right] => 100
    )
    

    【讨论】:

      【解决方案4】:

      没有必要为此使用正则表达式。您只需遍历字符串并根据需要构建数组。

      编辑,刚刚意识到使用 while 循环而不是两个 for 循环和 if() 可以更快地完成。

      $str ="(10*2)/(3*40)*100";
      $str = str_split($str); // make str an array
      
      $arr = array();
      $j=0; // counter for new array
      for($i=0;$i<count($str);$i++){ 
          if(is_numeric($str[$i])){ // if the item is a number
              $arr[$j] = $str[$i]; // add it to new array 
              $k = $i+1;
              while(is_numeric($str[$k])){ // while it's still a number append to new array item.
                  $arr[$j] .= $str[$k]; 
                  $k++; // add one to counter.
                  if($k == count($str)) break; // if counter is out of bounds, break loop.
              }
              $j++; // we are done with this item, add one to counter.
              $i=$k-1; // set new value to $i
          }else{
              // not number, add it to the new array and add one to array counter.
              $arr[$j] = $str[$i]; 
              $j++;
          }
      }
      
      var_dump($arr);
      

      https://3v4l.org/p9jZp

      【讨论】:

        【解决方案5】:

        你也可以使用这个匹配的正则表达式:[()+\-*\/]|\d+

        Demo

        【讨论】:

          【解决方案6】:

          我正在为一个 php 计算器演示做类似的事情。 A related post.

          考虑preg_split() 的这种模式:

          ~-?\d+|[()*/+-]~ (Pattern Demo)

          这有一个额外的好处,即允许负数而不会使操作员混淆它们。第一个“替代”匹配正整数或负整数,而第二个“替代”(在| 之后)匹配括号和运算符——一次一个。

          在 php 实现中,我将整个模式放在一个捕获组中并保留分隔符。这样就不会留下任何子字符串。 ~ 用作模式分隔符,这样模式中的斜线就不需要转义了。

          代码:(Demo)

          $expression = '(1*2)/(3*4)*100+-10';
          var_export(
              preg_split(
                  '~(-?\d+|[()*/+-])~',
                  $expression,
                  0,
                  PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
              )
          );
          

          输出:

          array (
            0 => '(',
            1 => '1',
            2 => '*',
            3 => '2',
            4 => ')',
            5 => '/',
            6 => '(',
            7 => '3',
            8 => '*',
            9 => '4',
            10 => ')',
            11 => '*',
            12 => '100',
            13 => '+',
            14 => '-10',
          )
          

          【讨论】:

          • @ChaitraHegde 在使用您的四个测试用例字符串比较当前接受的答案和我的模式之间的步骤效率时,我的方法将快大约 4 倍。如果您愿意,可以将此答案与我的其他帖子合并以允许使用小数。