忽略正则表达式中的第一个匹配项

Ignoring the first match in regex

本文关键字:第一个 正则表达式      更新时间:2023-10-16

我正在做一个来自C++Primer 的练习

重写您的手机程序,使其只写入拥有多部手机的人的第二个及后续电话号码数字

(电话程序只是使用正则表达式识别具有特定格式的电话号码)。

本章讨论了使用regex_replace和格式标志来更改中输入的电话号码的格式。问题是要求忽略输入的第一个电话号码,只格式化/打印第二个及后续电话号码。我的输入可能看起来像:

dave: 050 000 0020, (402)2031032, (999) 999-2222

并且应该输出

402.203.1032 999.999.2222

这是我的解决方案:

#include <iostream>
#include <string>
#include <regex>
using namespace std;
using namespace regex_constants;
int main(){
    string pattern = "(\()?(\d{3})(\))?([-. ])?(\d{3})([-. ])?(\d{4})";
    regex r(pattern);
    //string firstFormat = "";
    string secondFormat = "$2.$5.$7 ";
    for(string line; getline(cin, line);){
        unsigned counter = 0;
        for(sregex_iterator b(line.begin(), line.end(), r), e; b != e; ++b)
            if(++counter > 1) cout << (*b).format(secondFormat);
        cout << endl;
//      Below: iterates through twice, maybe not ideal
//      string noFirst = regex_replace(line, r, firstFormat, format_first_only); //removes the first phone number
//      cout << regex_replace(noFirst, r, secondFormat, format_no_copy) << endl;
    }

}

然而,我对使用计数器来确保我不会处理第一场比赛感到不满。感觉必须有一个更自然的实用程序(比如format_first_only标志,可以传递给format,除非相反),才能忽略第一个匹配?但我很难找到一个。

注释掉的解决方案似乎要好一点,只是它需要通过输入进行第二次迭代。

您可以使用G锚点。

"(?:(?!\A)\G|.*?\d{3}\D*\d{3}\D*\d{4}).*?(\d{3})\D*(\d{3})\D*(\d{4})"

secondFormat = "$1.$2.$3 ";
不需要柜台的地方。

格式化:

 (?:
      (?! A )                      # Not beginning of string
      G                            # End of previous match
   |                              # or,
      .*?                           # Anything up to
      d{3} D* d{3} D* d{4}     # First phone number
 )
 .*?                           # Anything up to
 ( d{3} )                     # (1), Next phone number
 D* 
 ( d{3} )                     # (2)
 D* 
 ( d{4} )                     # (3)

输入:

dave: 050 000 0020, (402)2031032, (999) 999-2221

输出:

 **  Grp 0 -  ( pos 0 , len 32 ) 
dave: 050 000 0020, (402)2031032  
 **  Grp 1 -  ( pos 21 , len 3 ) 
402  
 **  Grp 2 -  ( pos 25 , len 3 ) 
203  
 **  Grp 3 -  ( pos 28 , len 4 ) 
1032  
-------------------------------------
 **  Grp 0 -  ( pos 32 , len 16 ) 
, (999) 999-2221  
 **  Grp 1 -  ( pos 35 , len 3 ) 
999  
 **  Grp 2 -  ( pos 40 , len 3 ) 
999  
 **  Grp 3 -  ( pos 44 , len 4 ) 
2221  

如何将正则表达式更改为类似(?<=P, *)(P)的正则表达式(其中P是匹配电话号码的正则表达式的缩写)。换句话说,你只对前一个电话号码后面的电话号码感兴趣。

这个建议的唯一问题是C++似乎不支持正面的向后看。

(注意:您不希望所有捕获都在第一个电话号码中。)