python 使用命名组合解析结构化文本
使用命名组合来解析结构化的文本数据
有时候我们拿到的数据是以文本的形式逐条列出,而在输出文本时为了增加可读性,可能会将数据元素的描述信息写入进去,这样的结构化数据方便人工识别,但是对于数据的二次利用远不如csv,json
等结构化数据好用,为了提取其中有用的信息,可以使用python正则库中命名组合的方法来处理。
官方文档里对命名组合的说明:
(?P
…) 命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。组合名必须是有效的Python标识符,并且每个组合名只能用一个正则表达式定义,只能定义一次。一个符号组合同样是一个数字组合,就像这个组合没有被命名一样。命名组合可以在三种上下文中引用。如果样式是
(?P<quote>['"]).*?(?P=quote)
(也就是说,匹配单引号或者双引号括起来的字符串):
引用组合"quote"的上下文 引用方法 在正则式自身内 (?P=quote)
\1处理匹配对象 m m.group('quote')
m.end('quote')`传递到 re.sub()
里的 repl 参数中\g
\g<1>
\(?P=name)反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。
但具体怎么用呢?文档里并没有给出实例,这里结合一个具体的例子来说明一下用法:
例如对于下面的结构化字符串文本:
Student(name="John", age=18, grade=Grade(subject="English", mark=90))
如果想要拿到学生的各项信息,使用字符串查找会非常麻烦,而且不具有通用性,因此考虑使用python中的命名组合方式来提取。首先分析该字符串文本的结构,一个Student由三个属性组成:姓名name, 年龄age,学科成绩grade,其中grade属性本身也是一个结构化的文本数据,由两部分组成:学科subject和分数mark。
为了使我们的文本解析正则表达式具有更高的复用性,我们为该条字符串定义两组命名组合student_re和grade_re:
import re
grade_re = r'Grade[(]subject="(?P<subject>.*)", mark=(?P<mark>\d+)[)]'
student_re = r'Student[(]name="(?P<name>.*)", age=(?P<age>\d+), grade={grade}[)]'.format(grade=grade_re)
使用上述字符串进行测试,提取字符串中我们想要的属性字段数据:
match = re.match(student_re, test_str)
if match:
print(match.group('name'))
print(match.group('subject'))
输出:
John
English
结果符合我们的需要。因此我们只需要根据字符串的结构特征,将各字段的属性名称编写成正则命名组合,就能对任意形式的结构化字符串方便地进行提取了!