正则表达式与子进程输出的困境

时间:2015-10-08 10:29:18

标签: python regex

我试图匹配来自subprocess输出的IP和MAC地址,但似乎我有两个问题(我可以看到)。 regx不是很好,因为它缺少一些项目而另一个问题是,由于某种原因,OS X没有为arp -a命令生成正确的MAC地址输出。

我讨厌regx :(,我确实开始使用socket.inet_aton()来验证IP地址但迭代每一行并尝试将regx与mac匹配并使用socket.inet_aton(addr)进行验证并不是特别有用。所以决定在两个方面都使用regx。

我理解为什么不正确的格式化输出没有匹配(MAC)和那个问题我会在其他地方尝试地址,但我无法弄清楚为什么没有匹配正确格式化的输出。我提到过我讨厌过regx吗? :)

更新

我最初没有注意到以下行中的单个数字? (192.168.1.74) at fc:75:16:3:d0:2a on en0 ifscope [ethernet] # Not missing anything but does not match所以我的问题似乎是OSx没有正确打印MAC。由于某种原因,如果它是0,它看起来会脱离某个段的第一个数字。因此,我需要在任何单个数字段的前面添加一个0来解决我的问题(直到我弄清楚为什么它首先这样做。在其他系统上测试不会产生这个单个数字段在mac地址中。

脚本输出

? (192.168.1.74) at fc:75:16:3:d0:2a on en0 ifscope [ethernet] # Not missing anything but does not match
192.168.1.74
? (192.168.1.115) at 28:32:c5:f1:eb:9e on en0 ifscope [ethernet]
192.168.1.115
28:32:c5:f1:eb:9e
? (192.168.1.126) at 0:c:29:30:a1:c9 on en0 ifscope [ethernet] #Notice the misson 0 ?
192.168.1.126
gateway.home (192.168.1.254) at f4:55:9c:62:8a:cc on en0 ifscope [ethernet]
192.168.1.254
f4:55:9c:62:8a:cc
? (192.168.1.255) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet]
192.168.1.255
ff:ff:ff:ff:ff:ff
? (192.168.7.1) at 0:50:56:c0:0:8 on vmnet8 ifscope permanent [ethernet] #Notice the misson 0 ?
192.168.7.1
? (192.168.194.1) at 0:50:56:c0:0:1 on vmnet1 ifscope permanent [ethernet] #Notice the misson 0 ?
192.168.194.1

脚本

cmd="arp -a"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output, errrors = process.communicate()

for line in output.split("\n"):
    print line
    for data in line.split(' '):
        data = data.translate(None, '()')
        mac = re.match("^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$", data)
        if mac:
            print mac.group()
        ip = re.match("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", data)
        if ip:
            print ip.group()

2 个答案:

答案 0 :(得分:1)

MAC地址正则表达式(由@nhahtdh指出)不考虑单个数字(或字母)段,我也使用单个正则表达式(避免循环并减少代码)。 / p>

#!/usr/bin/python

import subprocess
import re

cmd = "arp -a"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output, errors = process.communicate()

for line in output.split("\n"):
    if line and not line.isspace():
        print "line ->", line
        regex = re.match("(?i).*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*?((?:[0-9A-F]{1,2}[:]){5}(?:[0-9A-F]{1,2}))", line)
        print "ip  ->", regex.group(1)
        print "mac ->", re.sub('(^[^:](?=:)|(?<=:)[^:](?=:)|(?<=:)[^:]$)', '0\\1', regex.group(2))

答案 1 :(得分:0)

当前接受的答案过于复杂。无需拆分字符串。您遇到的问题是^$与字符串的开头/结尾而不是行匹配。要使它们与行尾匹配,只需将re.MULTILINE传递给编译标志。

使用上面的脚本,它就是:

cmd="arp -a"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output, errrors = process.communicate()
mac_matcher = re.compile("^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$", re.M)
ip_matcher = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", re.M)
# I'm using search here to just get the first value, but you can iterate instead
mac = mac_matcher.search(output)
ip = ip_matcher.search(output)