匹配表达式但不匹配以 # 开头的行

Match an expression but don't match lines that start with a #

我是我们Qt。我有一个文本字符串,我专门寻找函数调用 xyz.set_name(),我想捕获此调用的最后一次出现,但如果包含它的行以 # 开头,则将其否定。到目前为止,我得到了正则表达式来匹配函数调用,但我不知道如何否定 # 匹配的行,我不知道如何捕获最后一次出现的内容,不知道为什么所有匹配项都是放入一个捕获组。

[().\w\d]+.set_name\(\)\s*

这就是我想要的

abc.set_name() // match
# abc.set_name() // don't match
xyz.set_name() // match and capture this one

更新以获取更多说明:

我用 qDebug 打印出来的文字是这样的

Hello\nx=y*2\nabc.set_name()   \n#xyz.set_name()

这是一个长字符串,\n作为换行符。

更新:用于测试的更长的测试字符串。我已经尝试了所有建议的正则表达式,但它们没有用。不知道缺少什么。 https://regex101.com/r/vXpXIA/1

更新2:Scratch我的第一个更新,\n是一个qDebug()的东西,使用regex时不需要考虑。

您需要正则表达式先行运算符(如果您的正则表达式引擎支持它)。这个will work.

(?(?=^[^#])(^\s*[a-zA-Z]+\.set_name\(\))|z^)

解释:

  • (?(?=patt)then|else) - 正则表达式 if-else 构造,如果正则表达式匹配给定模式 patt,则匹配 then,否则 else 是匹配

  • patt = ^[^#] -- 在行首,没有#

  • then part - 如果 patt 为真 - ^\s*[a-zA-Z]*\.set_name\(\) 匹配任意数量的空格后跟 <something>.set_name()其中 something 是变量名。

  • else part -- 如果 patt 为假 -- 匹配 z^ z 出现在行首之前,不可能。


编辑:刚刚意识到你可以在变量名中包含数字(但它不能以一个开头)。在那种情况下,改进的正则表达式(未测试)

(?(?=^[^#])(^\s*[a-zA-Z]+[a-zA-Z\d]*\.set_name\(\))|z^)

编辑:由于您的字符串中也有换行符,因此它与您问题中的问题描述不符。尽管如此,只需将字符串标记化就足够简单了。

只是根据新行拆分字符串。

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

int main()
{
    std::istringstream isr;
    isr.str("I am John\n today is  \n#abc.set_name()\n");
    std::string tok;
    std::vector<std::string> vs;
    while(std::getline(isr, tok))
    {
        std::cout << tok << std::endl;
        vs.push_back(tok);
    }
    
    for (auto r_it = vs.rbegin(); r_it != vs.rend(); ++r_it)
    {
        std::cout << *r_it << std::endl;
        // if match then break from loop
    }
}


如果您只想匹配匹配模式的最后一行

^[a-z]+\.set_name\(\)

你可以使用正则表达式。

(?smi)^[a-z]+\.set_name\(\)(?!.*^[a-z]+\.set_name\(\))

为简单起见,我使用了字符 class [a-z]。可以更改它以满足要求。题中是[().\w\d],可以简化为[().\w].

请注意,由于正在匹配感兴趣的子字符串,因此也没有必要捕获它。最后一行之前的一行以 '#' 开头的事实无关紧要。重要的是这些行是否匹配指定的模式。

Start your engine!

PCRE 正则表达式引擎执行以下操作。

(?smi)                  : set single-line, multi-line and case-indifferent
                          modes  
^                       : match the beginning of a line
[a-z]+\.set_name\(\)    : match 1+ chars in the char class, followed
                          by '.set_name\(\)'
(?!                     : begin negative-lookahead
.*^[a-z]+\.set_name\(\) : match 0+ chars (including newlines), the  
                          beginning of a line, 1+ letters, '\.set_name\(\)' 
)                       : end negative lookahead

回想一下,single-line 模式导致 . 匹配换行符,multi-line 模式导致 ^$ 匹配行的开头和结尾(而不是字符串的开头和结尾)。

您可以使用

(?s).*\n(?!\h*#)\h*([\w().]+\.set_name\(\))

查看 regex demo,您的比赛在第 1 组。详情

  • (?s) - DOTALL 模式开启,. 现在匹配任何字符
  • .* - 尽可能多的任意零个或多个字符
  • \n(?!\h*#) - 换行符后不紧跟 0 个或多个水平空格,然后是 # char
  • \h* - 0+ 水平空格
  • ([\w().]+\.set_name\(\)) - 捕获组 1:
    • [\w().]+ - 1 个或多个字符,)(.
    • \.set_name\(\) - .set_name() 字符串。