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_name2function_name4 不匹配(因为没有前导 :。但我看到即使 function_name1function_name3,它不做非贪婪匹配。fn_name.group()的输出是

:NameSpace2::ClassName1::function_name1

我有三个问题:

  1. 我希望从第 1 行中提取字符串“function_name1”,但非贪婪匹配似乎不起作用。为什么?
  2. 为什么第 3 行没有被提取?
  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.

  1. 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".

  1. Why is line 3 not being extracted?

因为我已经测试了你的正则表达式。它根本不起作用,不仅是第三行。

  1. 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