Python 正则表达式跨越多行

5

我正在使用Python和Pexpect从一些思科设备中收集一些信息,并且在提取棘手的小项目时,已经取得了很大的成功。但是,我担心我在这方面遇到了难题。有些交换机会堆叠在一起,我已经在脚本中识别出这一点,并使用单独的例程来解析数据。如果交换机被堆叠,则会看到以下内容(从sho ver输出中提取)

Top Assembly Part Number        : 800-25858-06
Top Assembly Revision Number    : A0
Version ID                      : V08
CLEI Code Number                : COMDE10BRA
Hardware Board Revision Number  : 0x01


Switch   Ports  Model              SW Version              SW Image
------   -----  -----              ----------              ----------
*    1   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M  
     2   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     3   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     4   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M


Switch 02 
---------
Switch Uptime                   : 11 weeks, 2 days, 16 hours, 27 minutes
Base ethernet MAC Address       : 00:26:52:96:2A:80
Motherboard assembly number     : 73-9675-15

当我遇到这种情况时,我需要从4个表格中提取每个开关的编号和型号(可以忽略sw,但是可能有1到9个开关)。多行的问题让我感到困扰,我已经处理好了其余部分。有什么建议吗?
抱歉,我的正则表达式只是从最后一组“-”开始查找,然后我就不知道该怎么办了! -{10]\s-{10}(.+)Switch
型号会改变,开关的数量也会改变,我需要捕获此示例中的4行内容。
*    1   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M  
     2   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     3   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     4   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M

但每个交换机可能是不同的型号,数量在1到9之间。对于这个例子,我希望得到以下结果:
*,1,WS-C3750-48P
,2,WS-C3750-48P
,3,WS-C3750-48P
,4,WS-C3750-48P  

(星号表示主节点)但是获取这些行将使我走上正确的轨道。

2
你可以发一下你尝试过的正则表达式代码吗?我不确定我完全理解你想要得到什么。 - Tom
2个回答

17
为了使 . 匹配包括换行符在内的任何字符,请在编译正则表达式时使用re.DOTALL 选项(请记住,如果您有多个选项,请使用位或运算符 | 将它们组合起来)。
在这种情况下,我不确定您是否实际上需要这样做-为什么不尝试像...这样的东西呢?
re.findall(r'(\d+)\s+\d+\s+(WS-\S+)')
假设你用 WS- 来识别“模型”?findall 的结果之间有换行并不影响。你能详细说明一下如何识别“模型”,以及为什么“多行模式”会成问题吗?也许你需要使用 re.MULTILINE,让 ^ 在每一行开头匹配,以便通过引用行的开头来获取数据...?

1
Alex,你又赶我一步了:-)。多行正则表达式的关键是re.DOTALL(这很令人困惑,因为你会认为它是re.MULTILINE)。但是,正如他指出的那样,在这种情况下,你不需要它,因为你要提取的数据在自己的行上:-)。此外,我喜欢alex使用\s+,表示一个或多个空格字符。还有一件事我可能会添加...我通常喜欢给我的组命名:(?P<model>WS-\S+)。 - Tom
嗯,你可能是对的 - 我会尝试一下然后回复你,但是由于我在英国,明天才能给你回复。非常感谢你的时间。 - user225882

8
x="""Top Assembly Part Number        : 800-25858-06
Top Assembly Revision Number    : A0
Version ID                      : V08
CLEI Code Number                : COMDE10BRA
Hardware Board Revision Number  : 0x01


Switch   Ports  Model              SW Version              SW Image
------   -----  -----              ----------              ----------
*    1   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     2   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     3   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M
     4   52     WS-C3750-48P       12.2(35)SE5             C3750-IPBASE-M


Switch 02
---------
Switch Uptime                   : 11 weeks, 2 days, 16 hours, 27 minutes
Base ethernet MAC Address       : 00:26:52:96:2A:80
Motherboard assembly number     : 73-9675-15"""

>>> import re
>>> re.findall("^\*?\s*(\d)\s*\d+\s*([A-Z\d-]+)",x,re.MULTILINE)
[('1', 'WS-C3750-48P'), ('2', 'WS-C3750-48P'), ('3', 'WS-C3750-48P'), ('4', 'WS-C3750-48P')]

更新: 因为原问题已被编辑,感谢Tom指出+号的问题。

>>> re.findall("^(\*?)\s+(\d)\s+\d+\s+([A-Z\d-]+)",x,re.MULTILINE)
[('*', '1', 'WS-C3750-48P'), ('', '2', 'WS-C3750-48P'), ('', '3', 'WS-C3750-48P'), ('', '4', 'WS-C3750-48P')]
>>>

+1 是因为我认为你很快地回答了这个问题 :-). 但是,为了清理一下...我会使用\s+而不是\s*。此外,在这种情况下,re.MULTILINE没有什么重要性。我相信你的解决方案可以在没有它的情况下正常工作 :-). - Tom
@Tom,嗯,你需要多行IF来匹配^的开头,就像我在我的答案中详细说明的那样--我不确定是否有必要与行首同步,这取决于如何识别“模型”。 - Alex Martelli
嗯,你上面的代码看起来没问题,但是你只解析了表格。你使用的字符串在一堆其他文本(请参见原始帖子)的中间,而表格则在其中间。我的数据上下可能有50行。 - user225882
顺便提一下,模型始终会以WS-开头。 - user225882
好的,我不确定它是否总是以WS-开头,我要更新一下。 - YOU
啊,这和Alex的答案完全一样,所以我不会更新它,相反请接受Alex的答案。谢谢。 - YOU

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