1

我是我们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()东西,使用正则表达式时不需要考虑。

4

3 回答 3

1

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

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

你可以使用正则表达式。

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

为简单起见,我使用了字符类[a-z]。可以根据需要进行更改。在问题中是[().\w\d],可以简化为[().\w]

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

启动你的引擎!

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

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

于 2020-08-08T03:40:54.480 回答
0

您需要正则表达式前瞻运算符(如果您的正则表达式引擎支持它)。这将起作用

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

解释:

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

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

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

  • else 部分——如果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
    }
}


于 2020-08-08T02:47:08.433 回答
0

您可以使用

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

请参阅正则表达式演示,您的比赛在第 1 组。详细信息

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