代码之家  ›  专栏  ›  技术社区  ›  bos570

正则表达式可以选择多次匹配模式

  •  1
  • bos570  · 技术社区  · 7 年前

    我有一个字符串,我想匹配一个特定的模式,可以选择的次数尽可能多。

    我的琴弦
    0.91 0.45 0.69 58 47 45 23 83 90 $595 NO IDL

    45 直到 $595 可能还有6个号码。我如何选择在该空间中查找重复编号?

    以下是我目前掌握的情况:

    /([\d.]+) ([\d.]+) ([\d.]+)? (\d+) (\d+) (\d+)  \$(\d+)/ig 
    

    以下是一些具有预期输出的示例:

    0.91 0.45 0.69 58 47 45 23 83 90 $595 NO IDL
    output: array([0] => 0.91, 
                  [1] => 0.45, 
                  [2] => 0.69, 
                  [3] => 58, 
                  [4] => 47, 
                  [5] => 45, 
                  [6] => 23, 
                  [7] => 83, 
                  [8] => 90, 
                  [9] => 595)
    
    0.91 0.45 0.69 58 47 45 $595 NO IDL
    output: array([0] => 0.91, 
                  [1] => 0.45, 
                  [2] => 0.69, 
                  [3] => 58, 
                  [4] => 47, 
                  [5] => 45,  
                  [5] => 595)
    
    0.91 0.45 0.69 0.63 58 47 45 $595 NO IDL
    output: Does not match the pattern because we only want 3 of the first items to contain decimals. 
    

    这似乎把最后一个数字分成多个数字。不知道发生了什么。

    我正在为此使用php preg_match方法,因此如果可能的话,不希望结果数组中的元素为空。谢谢。

    3 回复  |  直到 7 年前
        1
  •  1
  •   Wiktor Stribiżew    7 年前

    您可以使用字符串开头触发的正前视来验证字符串,然后在验证成功后将从开始到货币值的所有数字匹配起来:

    '~(?:\G(?!^)|^(?=\d+\.\d+ \d+\.\d+ \d+(?:\.\d+)?(?: \d+)* \$\d))\s*\$?\K\d+(?:\.\d+)?~'
    

    regex demo

    细节

    • (?:\G(?!^)|^(?=\d+\.\d+ \d+\.\d+ \d+(?:\.\d+)?(?: \d+)* \$\d)) -上一场比赛的结束( \G(?!^) )或字符串的开头( ^ )接下来是
      • \d+\.\d+
      • 一个空间
      • \d+\d++
      • -空间
      • \d+ - 1位数字
      • (?:\.\d+)? -可选的小数部分
      • (?: \d+)* -0+空格序列后跟1+数字
      • -空间
      • \$\d -A $ 还有一个数字。
    • \s* -0+空格
    • \$? -可选的 $ 烧焦
    • \K -匹配重置运算符
    • \d+(?:\.\d+)? -一个整数/浮点数(1+位,后跟可选的 . 以及1个以上的数字)。

    PHP demo :

    $strs = ['0.91 0.45 0.69 58 47 45 23 83 90 $595 NO IDL','0.91 0.45 0.69 58 47 45 $595 NO IDL','0.91 0.45 0.69 0.63 58 47 45 $595 NO IDL'];
    $rx = '~(?:\G(?!^)|^(?=\d+\.\d+ \d+\.\d+ \d+(?:\.\d+)?(?: \d+)* \$\d))\s*\$?\K\d+(?:\.\d+)?~';
    foreach ($strs as $s) {
        echo "$s:\n";
        if (preg_match_all($rx, $s, $matches)) {
            print_r($matches[0]);
            echo "---------\n";
        } else {
            echo "NO MATCH!!!\n---------\n";
        }
    
    }
    

    输出:

    0.91 0.45 0.69 58 47 45 23 83 90 $595 NO IDL:
    Array
    (
        [0] => 0.91
        [1] => 0.45
        [2] => 0.69
        [3] => 58
        [4] => 47
        [5] => 45
        [6] => 23
        [7] => 83
        [8] => 90
        [9] => 595
    )
    ---------
    0.91 0.45 0.69 58 47 45 $595 NO IDL:
    Array
    (
        [0] => 0.91
        [1] => 0.45
        [2] => 0.69
        [3] => 58
        [4] => 47
        [5] => 45
        [6] => 595
    )
    ---------
    0.91 0.45 0.69 0.63 58 47 45 $595 NO IDL:
    NO MATCH!!!
    ---------
    
        2
  •  0
  •   Mike Jouwstra    7 年前

    这将给您带来预期的结果:

    /([\d\$.]+)/ig
    
        3
  •  0
  •   The fourth bird    7 年前

    你可以重复这些数字直到你匹配 45 这是第六个号码。

    解释

    • (?:\d+\.\d+)(?: \d+\.\d+){2} 将开头的数字(带小数部分的数字)匹配3次
    • (?: \d+){3} 将数字与空白匹配3次。到45岁为止
    • \s* 匹配零个或多个空白字符
    • |
    • \G(?!^) 使用负的lookahead断言前一个匹配项末尾的位置,而不是字符串的开头
    • (\d+)\s 捕获数字并匹配捕获组中的空白

    (?:\d+\.\d+)(?: \d+\.\d+){2}(?: \d+){3}\s*|\G(?!^)(\d+)\s

    Regex demo

    例如,演示如何提取45后的3位数:

    Demo