Python多行正则表达式

7

我遇到了一个编译多行匹配正则表达式的问题,能否有人指出我做错了什么。我正在循环遍历一个包含数百个条目的基本dhcpd.conf文件,例如:

host node20007                                                                                                                  
{                                                                                                                              
    hardware ethernet 00:22:38:8f:1f:43;                                                                                       
    fixed-address node20007.domain.com;     
}

我已经成功使用各种正则表达式来匹配MAC地址和固定IP地址,但是无法将它们组合起来正确匹配。

f = open('/etc/dhcp3/dhcpd.conf', 'r')
re_hostinfo = re.compile(r'(hardware ethernet (.*))\;(?:\n|\r|\r\n?)(.*)',re.MULTILINE)

for host in f:
match = re_hostinfo.search(host)
    if match:
        print match.groups()

目前,我的匹配结果如下:
('hardware ethernet 00:22:38:8f:1f:43', '00:22:38:8f:1f:43', '')

但是我想寻找下面这样的结果:
('hardware ethernet 00:22:38:8f:1f:43', '00:22:38:8f:1f:43', 'node20007.domain.com')


如果文件恰好是这种格式,那么最好的方法可能是在空格上拆分行,并将末尾的元素作为值。 - mmmmmm
2个回答

13

更新 我刚刚注意到你得到结果的真正原因; 在你的代码中:

for host in f:
    match = re_hostinfo.search(host)
    if match:
        print match.groups()

host指的是单行,但您的模式需要在两行上工作。

尝试这样做:

data = f.read()
for x in regex.finditer(data):
    process(x.groups())

其中 regex 是一个编译好的模式,可以匹配两行文本。

如果你的文件很大,并且你确定感兴趣的部分总是分布在两行中,那么你可以逐行读取文件,检查该行是否符合模式的第一部分,并设置一个标志来告诉你下一行是否应该检查第二部分。如果不确定,这就变得复杂了,可能需要开始看一下pyparsing模块。

现在回到原始答案,讨论你应该使用的模式:

你不需要使用 MULTILINE;只需要匹配空格即可。使用以下构建块构建你的模式:

(1) 固定文本 (2) 一个或多个空格字符 (3) 一个或多个非空格字符

然后将它们放在括号中以获取你的组。

尝试这个:

>>> m = re.search(r'(hardware ethernet\s+(\S+));\s+\S+\s+(\S+);', data)
>>> print m.groups()
('hardware ethernet   00:22:38:8f:1f:43', '00:22:38:8f:1f:43', 'node20007.domain.com')
>>>
请考虑使用“详细模式”……您可以使用它来记录模式匹配哪些数据,通常可以帮助在第一次正确地获取模式。例如:
>>> regex = re.compile(r"""
... (hardware[ ]ethernet \s+
...     (\S+) # MAC
... ) ;
... \s+ # includes newline
... \S+ # variable(??) text e.g. "fixed-address"
... \s+
... (\S+) # e.g. "node20007.domain.com"
... ;
... """, re.VERBOSE)
>>> print regex.search(data).groups()
('hardware ethernet   00:22:38:8f:1f:43', '00:22:38:8f:1f:43', 'node20007.domain.com')
>>>

0
有时候,更简单的方法并不是使用正则表达式。这只是一个例子。
for line in open("dhcpd.conf"):
    line = line.rstrip()
    sline = line.split()
    if "hardware ethernet" or "fixed-address" in line:
       print sline[-1]

另一种方式

data = open("file").read().split("}");
for item in data:
    item = [ i.strip() for i in item.split("\n") if i != '' ];
    for elem in item:
       if "hardware ethernet" in elem:
           print elem.split()[-1]
    if item: print  item[-1]

输出

$ more file
host node20007
{
    hardware ethernet 00:22:38:8f:1f:43;
        fixed-address node20007.domain.com;
}

host node20008
{
    hardware ethernet 00:22:38:8f:1f:44;
        some-address node20008.domain.com;
}

$ python test.py
00:22:38:8f:1f:43;
fixed-address node20007.domain.com;
00:22:38:8f:1f:44;
some-address node20008.domain.com;

但请注意,OP似乎并不在意“硬件以太网”后面的行是否包含“固定地址”... - John Machin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,