关于python:从包含括号(日志文件)的文本中提取键值对

Extract key-value pairs from text containing brackets (log files)

假设这个字符串:

1
[aaa   ] some text here [bbbb3 ] some other text here [cc    ] more text

我想要一个像这样的关键值对:

1
2
3
4
Key      Value
aaa      some text here  
bbbb3    some other text here  
cc       more text

或像这样的pandas DataFrame

1
2
3
4
aaa            | bbbb3                |cc
-------------------------------------------------
some text here | some other text here | more text
next line      | .....                | .....

我尝试了一个正则表达式:r'\[(.{6})\]\s(.*?)\s\[',但这不起作用。


使用re.findall,并将感兴趣的区域提取到列中。然后,您可以根据需要删除空格。

由于您提到您可以将其读入DataFrame,因此您可以将该作业留给pandas。

1
2
3
4
5
import re
matches = re.findall(r'\[(.*?)\](.*?)(?=\[|$)', text)

df = (pd.DataFrame(matches, columns=['Key', 'Value'])
        .apply(lambda x: x.str.strip()))

1
2
3
4
5
df
     Key                 Value
0    aaa        some text here
1  bbbb3  some other text here
2     cc             more text

或者(Re:编辑),

1
2
3
4
5
6
7
df = (pd.DataFrame(matches, columns=['Key', 'Value'])
        .apply(lambda x: x.str.strip())
        .set_index('Key')
        .transpose())

Key               aaa                 bbbb3         cc
Value  some text here  some other text here  more text

该模式匹配大括号内的文本,然后是文本外部到下一个左大括号。

1
2
3
4
5
6
7
8
9
\[      # Opening square brace
(.*?)   # First capture group
\]      # Closing brace
(.*?)   # Second capture group
(?=     # Look-ahead
   \[   # Next brace,
   |    # Or,
   $    # EOL
)


试试这个正则表达式,它捕获您在命名组捕获中的键和值。

1
\[\s*(?P<key>\w+)+\s*]\s*(?P<value>[^[]*\s*)

说明:

  • \[ - >由于[具有定义字符集的特殊含义,因此需要对其进行转义并与文字[匹配
  • \s* - >在不需要键的一部分的预期键之前消耗任何前面的空格
  • (?P\w+)+ - >形成一个key命名组,捕获一个或多个单词[a-zA-Z0-9_]字符。我使用\w来保持简单,因为OP的字符串只包含字母数字字符,否则应该使用[^]]字符集来捕获方括号内的所有内容作为键。
  • \s* - >在预期的密钥捕获之后消耗任何后续空间,而不需要密钥的一部分
  • ] - >匹配不需要转义的文字]
  • \s* - >消耗任何不需要成为值的一部分的前面空格
  • (?P[^[]*\s*) - >形成一个value命名组,捕获任何字符异常[,此时它将停止捕获并将捕获的值分组到命名组value中。

演示

Python代码,

1
2
3
4
5
import re
s = '[aaa   ] some text here [bbbb3 ] some other text here [cc    ] more text'

arr = re.findall(r'\[\s*(?P<key>\w+)+\s*]\s*(?P<value>[^[]*\s*)', s)
print(arr)

输出,

1
[('aaa', 'some text here '), ('bbbb3', 'some other text here '), ('cc', 'more text')]


这里并不真正需要正则表达式 - 简单的字符串拆分可以完成工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
s ="[aaa   ] some text here [bbbb3 ] some other text here [cc    ] more text"    

parts = s.split("[")  # parts looks like: ['',
                      #                    'aaa   ] some text here ',
                      #                    'bbbb3 ] some other text here ',
                      #                    'cc    ] more text']
d = {}
# split parts further
for p in parts:
    if p.strip():
        key,value = p.split("]")            # split each part at ] and strip spaces
        d[key.strip()] = value.strip()      # put into dict

# Output:
form ="{:10} {}"
print( form.format("Key","Value"))

for i in d.items():
      print(form.format(*i))

输出:

1
2
3
4
Key        Value
cc         more text
aaa        some text here
bbbb3      some other text here

Doku格式化:

  • 自定义字符串格式化
  • 字符串格式迷你语言

几乎是1班轮:

1
d = {hh[0].strip():hh[1].strip() for hh in (k.split("]") for k in s.split("[") if k)}

您可以通过使用re.split()并输出到字典来最小化所需的正则表达式。例如:

1
2
3
4
5
6
7
8
9
10
11
12
import re

text = '[aaa   ] some text here [bbbb3 ] some other text here [cc    ] more text'

# split text on"[" or"]" and slice off the first empty list item
items = re.split(r'[\[\]]', text)[1:]

# loop over consecutive pairs in the list to create a dict
d = {items[i].strip(): items[i+1].strip() for i in range(0, len(items) - 1, 2)}

print(d)
# {'aaa': 'some text here', 'bbbb3': 'some other text here', 'cc': 'more text'}


使用RegEx,您可以找到key,value对,将它们存储在字典中并打印出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

mystr ="[aaa   ] some text here [bbbb3 ] some other text here [cc    ] more text"

a = dict(re.findall(r"\[([A-Za-z0-9_\s]+)\]([A-Za-z0-9_\s]+(?=\[|$))", mystr))

for key, value in a.items():
    print key, value

# OUTPUT:
# aaa     some text here
# cc      more text
# bbbb3   some other text here

RegEx匹配2组:
第一组是用方括号括起来的所有字符,数字和空格,第二组是所有字符,数字和空格,前面是一个封闭的方括号,后面是一个空方括号或行的末尾

第一组:\[([A-Za-z0-9_\s]+)\]
第二组:([A-Za-z0-9_\s]+(?=\[|$))

请注意,在第二组中,我们有一个积极的前瞻:(?=\[|$)。没有正向前瞻,角色将被消耗,下一组将找不到起始方括号。

然后findall返回一个元组列表:[(key1,value1), (key2,value2), (key3,value3),...]
元组列表可以立即转换为字典:dict(my_tuple_list)。

一旦你有了dict,你可以用你的键/值对做你想做的事:)


你可以使用finditer:

1
2
3
4
5
6
7
import re

s = '[aaa   ] some text here [bbbb3 ] some other text here [cc    ] more text'

pattern = re.compile('\[(\S+?)\s+\]([\s\w]+)')
result = [(match.group(1).strip(), match.group(2).strip()) for match in pattern.finditer(s)]
print(result)

产量

1
[('aaa', 'some text here'), ('bbbb3', 'some other text here'), ('cc', 'more text')]