Python 使用多种字符串格式解析挑战

Python 使用多种字符串格式解析挑战,python,regex,Python,Regex,我试图解析设备日志,但格式不一致 例如: Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161 RSSI: -70 Roam candidate#10 F4:CF:E2:62:02:2F on channel 11 RSSI: -70 我想提取Mac地址、通道和RSSI值 不幸的是,在候选值变为10或更高之后,空格被省略 我试图将其标记化,但我几乎不理解这个过程 def clean(string): result = ""

我试图解析设备日志,但格式不一致

例如:

Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161  RSSI: -70

Roam candidate#10 F4:CF:E2:62:02:2F on channel 11  RSSI: -70
我想提取Mac地址、通道和RSSI值
不幸的是,在候选值变为10或更高之后,空格被省略

我试图将其标记化,但我几乎不理解这个过程

def clean(string):
    result = ""
    for i,char in enumerate(line):
        if char == " ":
            if string[i+1].isdigit() or string[i+1] == " ":
                continue
        result += char
    return result

def tokenize(string):
    result = []
    previous = 0
    for i,char in enumerate(string):
        if char == " ":
            result.append(string[previous:i])
            previous = i+1
        elif i == len(string)-1:
            result.append(string[previous:i+1])
    return result

我只将最后一列(RSSI)作为输出

如果要使用模式,可以使用3个捕获组,1个用于mac地址,1个用于通道,1个用于RSSI值:

Roam candidate# ?\d+ ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]){2}) on channel (\d+) +RSSI: (-?\d+)
小部分:

  • 漫游候选#?\d+
    匹配漫游候选#,可选空格和1+位数
  • ((?:[0-9A-Fa-f]{2}[:-]){5}(?[0-9A-Fa-f]){2})
    捕获组1,匹配mac地址
  • 在频道上(\d+)+
    在频道上匹配,空格后按2组1+数字捕获
  • RSSI:(?\d+)
    匹配RSSI:、空格并在第3组中捕获可选的
    -
    和1+位数
|

比如说

import re

strings = ["Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161  RSSI: -70", "Roam candidate#10 F4:CF:E2:62:02:2F on channel 11  RSSI: -70"]
regex = r"Roam candidate# ?\d+ ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]){2}) on channel (\d+) +RSSI: (-?\d+)"
for s in strings:
    print(re.findall(regex, s, re.M))
结果

[('F4:CF:E2:5E:73:3F','161','-70')]

[('F4:CF:E2:62:02:2F','11','70')]


如果要使用模式,可以使用3个捕获组,1个用于mac地址,1个用于通道,1个用于RSSI值:

Roam candidate# ?\d+ ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]){2}) on channel (\d+) +RSSI: (-?\d+)
小部分:

  • 漫游候选#?\d+
    匹配漫游候选#,可选空格和1+位数
  • ((?:[0-9A-Fa-f]{2}[:-]){5}(?[0-9A-Fa-f]){2})
    捕获组1,匹配mac地址
  • 在频道上(\d+)+
    在频道上匹配,空格后按2组1+数字捕获
  • RSSI:(?\d+)
    匹配RSSI:、空格并在第3组中捕获可选的
    -
    和1+位数
|

比如说

import re

strings = ["Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161  RSSI: -70", "Roam candidate#10 F4:CF:E2:62:02:2F on channel 11  RSSI: -70"]
regex = r"Roam candidate# ?\d+ ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]){2}) on channel (\d+) +RSSI: (-?\d+)"
for s in strings:
    print(re.findall(regex, s, re.M))
结果

[('F4:CF:E2:5E:73:3F','161','-70')]

[('F4:CF:E2:62:02:2F','11','70')]


对于regex,它的工作原理如下:

import re
s1="Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161 RSSI: -70"
s2="Roam candidate#10 F4:CF:E2:62:02:2F on channel 11 RSSI: -70"

patt= re.compile('(?P<mac>[0-9A-F]{2}(:[0-9A-F]{2}){5}).*?channel (?P<channel>[0-9]*).*?RSSI:\s*(?P<rssi>-?[0-9]*)', re.I)

matcher= patt.search(s1)

print(matcher.group('mac'))
print(matcher.group('channel'))
print(matcher.group('rssi'))
第二行:

F4:CF:E2:62:02:2F
11
-70

对于regex,它的工作原理如下:

import re
s1="Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161 RSSI: -70"
s2="Roam candidate#10 F4:CF:E2:62:02:2F on channel 11 RSSI: -70"

patt= re.compile('(?P<mac>[0-9A-F]{2}(:[0-9A-F]{2}){5}).*?channel (?P<channel>[0-9]*).*?RSSI:\s*(?P<rssi>-?[0-9]*)', re.I)

matcher= patt.search(s1)

print(matcher.group('mac'))
print(matcher.group('channel'))
print(matcher.group('rssi'))
第二行:

F4:CF:E2:62:02:2F
11
-70

另一种正则表达式方法:

import re

lines = '''Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161  RSSI: -70
Roam candidate#10 F4:CF:E2:62:02:2F on channel 11  RSSI: -70'''

pat = re.compile(r'(?<=#)\s*\d+\s+((?:[A-F0-9]{2}:){5}[A-F0-9]{2}) .*channel\s+(\d+)\s+RSSI:\s+(-?\d+)', re.I)
for line in lines.split('\n'):
    print(pat.findall(line))

另一种正则表达式方法:

import re

lines = '''Roam candidate# 9 F4:CF:E2:5E:73:3F on channel 161  RSSI: -70
Roam candidate#10 F4:CF:E2:62:02:2F on channel 11  RSSI: -70'''

pat = re.compile(r'(?<=#)\s*\d+\s+((?:[A-F0-9]{2}:){5}[A-F0-9]{2}) .*channel\s+(\d+)\s+RSSI:\s+(-?\d+)', re.I)
for line in lines.split('\n'):
    print(pat.findall(line))

简单的事情可能更好

r”(?i)([a-f0-9]{2}(?:[a-f0-9]{2})+\s.*\s(\d+)\s.*\s(-)\d+)

扩大

 (?i)
 (                             # (1 start)
      [a-f0-9]{2} 
      (?: : [a-f0-9]{2} )+
 )                             # (1 end)
 \s .*? \s 
 ( \d+ )                       # (2)
 \s .*? \s 
 ( -? \d+ )                    # (3)

简单的事情可能更好

r”(?i)([a-f0-9]{2}(?:[a-f0-9]{2})+\s.*\s(\d+)\s.*\s(-)\d+)

扩大

 (?i)
 (                             # (1 start)
      [a-f0-9]{2} 
      (?: : [a-f0-9]{2} )+
 )                             # (1 end)
 \s .*? \s 
 ( \d+ )                       # (2)
 \s .*? \s 
 ( -? \d+ )                    # (3)

下面是一个使用命名捕获组的正则表达式。您可以将鼠标悬停在对象上以了解它们的功能:下面是一个使用命名捕获组的正则表达式。您可以将鼠标悬停在对象上以了解它们的作用:在我的情况下,我需要从日志文件中提取许多字符串。这些值来自包含“ConstructionNeightarCacheFromBeacon”的行,因此我将仅对这些值进行筛选lines@EricGarnel因此,在我的例子中,如果你想从字面上匹配开始,我需要从日志文件中提取许多字符串。这些值来自包含“ConstructionNeightarCacheFromBeacon”的行,因此我将仅对这些值进行筛选lines@EricGarnel因此,您希望从字面上匹配开始,这正是我要查找的输出,但我一直在研究如何将包含特定单词的行读入数组(代替示例中的lines语句)。其中包含单词beaconcache的示例行。谢谢,我就是这样解决的:#/usr/bin/python#import sys,re arr=[],open('file.txt',r')作为f:for f.readlines()中的行:如果行中的'constructNeightRCacheFromBeaConCache':#print(line)arr.append(line)regex=r“Roam候选者#?\d+(?:[0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]){f]){2}在通道上(+RSSI:-){对于arr:print(re.findall(regex,s,re.M))中的s,这正是我要寻找的输出,但我一直在研究如何将包含特定单词的行读入数组(代替示例中的lines语句)。其中包含单词beaconcache的示例行。谢谢,我就是这样解决的:#/usr/bin/python#import sys,re arr=[],open('file.txt',r')作为f:for f.readlines()中的行:如果行中的'constructNeightRCacheFromBeaConCache':#print(line)arr.append(line)regex=r“Roam候选者#?\d+(?:[0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]){f]){2}在通道上(+RSSI:-){对于arr中的s:打印(关于findall(regex,s,re.M))