匹配表达式但不匹配以 # 开头的行
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]
.
请注意,由于正在匹配感兴趣的子字符串,因此也没有必要捕获它。最后一行之前的一行以 '#'
开头的事实无关紧要。重要的是这些行是否匹配指定的模式。
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()
字符串。
我是我们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]
.
请注意,由于正在匹配感兴趣的子字符串,因此也没有必要捕获它。最后一行之前的一行以 '#'
开头的事实无关紧要。重要的是这些行是否匹配指定的模式。
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()
字符串。