Python 正则表达式 - 非贪婪匹配不起作用
Python Regex - non-greedy match does not work
我有一个平面文件,其中包含一个 C++ 函数名称及其声明的一部分,如下所示:
virtual void NameSpace1::NameSpace2::ClassName1::function_name1(int arg1) const
void function_name2
void NameSpace2::NameSpace4::ClassName2::function_name3
function_name4
我正在尝试使用这一行单独提取函数名称:
fn_name = re.match(":(.*?)\(?", lines)
我能理解为什么 function_name2
和 function_name4
不匹配(因为没有前导 :
。但我看到即使 function_name1
和 function_name3
,它不做非贪婪匹配。fn_name.group()
的输出是
:NameSpace2::ClassName1::function_name1
我有三个问题:
- 我希望从第 1 行中提取字符串“
function_name1
”,但非贪婪匹配似乎不起作用。为什么?
- 为什么第 3 行没有被提取?
- 如何使用单个正则表达式从所有行中获取函数名称?
请帮忙。
1) 始终使用 r" "
字符串作为正则表达式。
2)
I am trying to extract the function names alone by using this line:
fn_name = re.match(":(.*?)\(?", lines)
The output of fn_name.group() is
:NameSpace2::ClassName1::function_name1
我没看到:
import re
line = "virtual void NameSpace1::NameSpace2::ClassName1::function_name1(int arg1) const"
fn_name = re.search(r":(.*?)\(?", line)
print(fn_name.group())
--output:--
:
无论如何,如果您想了解非贪婪算法是如何工作的,请看这段代码:
import re
line = "N----1----2"
greedy_pattern = r"""
N
.*
\d
"""
match_obj = re.search(greedy_pattern, line, flags=re.X)
print(match_obj.group())
non_greedy_pattern = r"""
N
.*?
\d
"""
match_obj = re.search(non_greedy_pattern, line, flags=re.X)
print(match_obj.group())
--output:--
N----1----2
N----1
非贪婪版本要求匹配 .*
的所有字符,直到遇到第一个数字,而贪婪版本将尝试找到随后的 .*
的最长匹配一个数字。
3) 警告!没有正则表达式区域!
func_names = [
"virtual void NameSpace1::NameSpace2::ClassName1::function_name1(int arg1) const",
"void function_name2",
"void NameSpace2::NameSpace4::ClassName2::function_name3",
"function_name4",
]
for func_name in func_names:
name = func_name.rsplit("::", 1)[-1]
pieces = name.rsplit(" ", 1)
if pieces[-1] == "const":
name = pieces[-2]
else:
name = pieces[-1]
name = name.split('(', 1)[0]
print(name)
--output:--
function_name1
function_name2
function_name3
function_name4
这个效果很好,至少你的例子:
^(?:\w+ +)*(?:\w+::)*(\w+)
即,在 Python 代码中:
import re
function_name = re.compile(r'^(?:\w+ +)*(?:\w+::)*(\w+)', re.MULTILINE)
matches = function_name.findall(your_txt)
# -> ['function_name1', 'function_name2', 'function_name3', 'function_name4']
要点:如果可以用贪心匹配来做,就用贪心匹配来做。
请注意,对于 C 标识符,\w
不正确 ,但写下与这些匹配的技术上正确的字符 class 是除此之外的问题。查找并使用正确的字符集而不是 \w
.
- I expected just the string "function_name1" to be extracted from line 1, but the non-greedy match does not seem to work. Why?
这是您的正则表达式的结果 ":(.*?)\(?"
我认为你的正则表达式是 "Too Lazy"。它只会匹配 :
因为 (.*?)
代表匹配任何字符 "as less as possible" 然后正则表达式引擎选择匹配 零字符 。它不会像您预期的那样匹配到 \(?
因为 ?
只是意味着 "optional".
- Why is line 3 not being extracted?
因为我已经测试了你的正则表达式。它根本不起作用,不仅是第三行。
- How do I get the function names from all the lines using a single regex?
你可以从这个最小的例子开始
(?:\:\:|void\s+)(\w+)(?:\(|$)|(function_name4)
其中 (?:\:\:|void\s+)
代表函数名称前导的任何内容,(?:\(|$)
代表函数名称后面的任何内容。
请注意,由于缺少模式,function_name4
应该明确声明。
参见:DEMO
我以前在尝试从 "N foo bar N----1----2" 捕获 "N----1" 时被类似的事情难住了。添加前导 .* 给出了预期的结果。
import re
line = "N foo bar N----1----2"
match_obj = re.search(r'(N.*?\d)', line)
print(match_obj.group(1))
match_obj = re.search(r'.*(N.*?\d)', line)
print(match_obj.group(1))
--output:--
N foo bar N----1
N----1
我有一个平面文件,其中包含一个 C++ 函数名称及其声明的一部分,如下所示:
virtual void NameSpace1::NameSpace2::ClassName1::function_name1(int arg1) const
void function_name2
void NameSpace2::NameSpace4::ClassName2::function_name3
function_name4
我正在尝试使用这一行单独提取函数名称:
fn_name = re.match(":(.*?)\(?", lines)
我能理解为什么 function_name2
和 function_name4
不匹配(因为没有前导 :
。但我看到即使 function_name1
和 function_name3
,它不做非贪婪匹配。fn_name.group()
的输出是
:NameSpace2::ClassName1::function_name1
我有三个问题:
- 我希望从第 1 行中提取字符串“
function_name1
”,但非贪婪匹配似乎不起作用。为什么? - 为什么第 3 行没有被提取?
- 如何使用单个正则表达式从所有行中获取函数名称?
请帮忙。
1) 始终使用 r" "
字符串作为正则表达式。
2)
I am trying to extract the function names alone by using this line:
fn_name = re.match(":(.*?)\(?", lines)
The output of fn_name.group() is
:NameSpace2::ClassName1::function_name1
我没看到:
import re
line = "virtual void NameSpace1::NameSpace2::ClassName1::function_name1(int arg1) const"
fn_name = re.search(r":(.*?)\(?", line)
print(fn_name.group())
--output:--
:
无论如何,如果您想了解非贪婪算法是如何工作的,请看这段代码:
import re
line = "N----1----2"
greedy_pattern = r"""
N
.*
\d
"""
match_obj = re.search(greedy_pattern, line, flags=re.X)
print(match_obj.group())
non_greedy_pattern = r"""
N
.*?
\d
"""
match_obj = re.search(non_greedy_pattern, line, flags=re.X)
print(match_obj.group())
--output:--
N----1----2
N----1
非贪婪版本要求匹配 .*
的所有字符,直到遇到第一个数字,而贪婪版本将尝试找到随后的 .*
的最长匹配一个数字。
3) 警告!没有正则表达式区域!
func_names = [
"virtual void NameSpace1::NameSpace2::ClassName1::function_name1(int arg1) const",
"void function_name2",
"void NameSpace2::NameSpace4::ClassName2::function_name3",
"function_name4",
]
for func_name in func_names:
name = func_name.rsplit("::", 1)[-1]
pieces = name.rsplit(" ", 1)
if pieces[-1] == "const":
name = pieces[-2]
else:
name = pieces[-1]
name = name.split('(', 1)[0]
print(name)
--output:--
function_name1
function_name2
function_name3
function_name4
这个效果很好,至少你的例子:
^(?:\w+ +)*(?:\w+::)*(\w+)
即,在 Python 代码中:
import re
function_name = re.compile(r'^(?:\w+ +)*(?:\w+::)*(\w+)', re.MULTILINE)
matches = function_name.findall(your_txt)
# -> ['function_name1', 'function_name2', 'function_name3', 'function_name4']
要点:如果可以用贪心匹配来做,就用贪心匹配来做。
请注意,对于 C 标识符,\w
不正确 ,但写下与这些匹配的技术上正确的字符 class 是除此之外的问题。查找并使用正确的字符集而不是 \w
.
- I expected just the string "function_name1" to be extracted from line 1, but the non-greedy match does not seem to work. Why?
这是您的正则表达式的结果 ":(.*?)\(?"
我认为你的正则表达式是 "Too Lazy"。它只会匹配 :
因为 (.*?)
代表匹配任何字符 "as less as possible" 然后正则表达式引擎选择匹配 零字符 。它不会像您预期的那样匹配到 \(?
因为 ?
只是意味着 "optional".
- Why is line 3 not being extracted?
因为我已经测试了你的正则表达式。它根本不起作用,不仅是第三行。
- How do I get the function names from all the lines using a single regex?
你可以从这个最小的例子开始
(?:\:\:|void\s+)(\w+)(?:\(|$)|(function_name4)
其中 (?:\:\:|void\s+)
代表函数名称前导的任何内容,(?:\(|$)
代表函数名称后面的任何内容。
请注意,由于缺少模式,function_name4
应该明确声明。
参见:DEMO
我以前在尝试从 "N foo bar N----1----2" 捕获 "N----1" 时被类似的事情难住了。添加前导 .* 给出了预期的结果。
import re
line = "N foo bar N----1----2"
match_obj = re.search(r'(N.*?\d)', line)
print(match_obj.group(1))
match_obj = re.search(r'.*(N.*?\d)', line)
print(match_obj.group(1))
--output:--
N foo bar N----1
N----1