python - 正则表达式仅匹配具有特定名称('naslov')的书('knjiga')
问题描述
我有一个简单的 xml:
<?xml version="1.0" encoding="utf-8" ?>
<book_list>
<book rbr="1" >
<title> Yacc </title>
<author> Filip Maric </author>
<year> 2004 </year>
<publisher> Matematicki fakultet </publisher>
<price currency="din"> 100 </price>
</book>
<book rbr="2" >
<author> Fredrik Lundh </author>
<price currency="eur"> 50 </price>
<publisher> O’Reilly & Associates </publisher>
<year> 2001 </year>
<title> Python Standard Library </title>
</book>
</book_list>
我需要将具有特定名称的书与 Python 中的正则表达式匹配。我可以轻松地将任何书籍与:
r'<book\s*rbr="\d+"\s*>.*?</book>'
(单行模式),然后检查它是否是正确的,但如果我想匹配特定的书 - 例如,Python标准库,直接使用正则表达式,我无法正确。如果我尝试
r'<book\s*rbr="\d+"\s*>(?P<book>.*?<title> Python Standard Library </title>.*?)</book>'
,在单行模式下,它会从头开始匹配所有内容,我明白为什么,但我找不到只匹配一个书标签的方法。我尝试了所有查找和所有不同的模式,但没有成功。
什么是正确的方法,它适用于 book_list 中的任意数量的书籍?
解决方案
由于<title>
标签并非始终是<book>
. 如果是,您可以使用:
m = re.search(r'<book\s*rbr="\d+"\s*>\s*(?P<book><title> Python Standard Library </title>).*?</book>', xml, flags=re.DOTALL)
也就是说,替换.*?
为\s*
.
诀窍是确保在您匹配一个<book>
标签之后,<title>
您正在寻找的标签不会出现在未来</book>
标签之后。这可以通过负面的前瞻来完成(它并不漂亮):
import re
xml = """<?xml version="1.0" encoding="utf-8" ?>
<book_list>
<book rbr="1" >
<title> Yacc </title>
<author> Filip Maric </author>
<year> 2004 </year>
<publisher> Matematicki fakultet </publisher>
<price currency="din"> 100 </price>
</book>
<book rbr="2" >
<author> Fredrik Lundh </author>
<price currency="eur"> 50 </price>
<publisher> O’Reilly & Associates </publisher>
<year> 2001 </year>
<title> Python Standard Library </title>
</book>
</book_list>"""
m = re.search(r'<book\s*rbr="\d+"\s*>(?!.*</book>.*<title> Python Standard Library </title>).*(?P<book><title> Python Standard Library </title>).*?</book>', xml, flags=re.DOTALL)
print(m.group('book'))
m = re.search(r'<book\s*rbr="\d+"\s*>(?!.*</book>.*<title> Yacc </title>).*(?P<book><title> Yacc </title>).*?</book>', xml, flags=re.DOTALL)
print(m.group('book'))
印刷:
<title> Python Standard Library </title>
<title> Yacc </title>
如果您的 Python 支持,您可以使用格式化的字符串文字来减少冗余(str.format
如果不支持,则使用该方法):
title = '<title> Python Standard Library </title>'
m = re.search(rf'<book\s*rbr="\d+"\s*>(?!.*</book>.*{title}).*(?P<book>{title}).*?</book>', xml, flags=re.DOTALL)
另一种方法
这种方法构建了所有单个<book>
标签的列表,然后搜索每个标签以查找感兴趣的标题:
# create list of <book> ... </book> strings:
books = re.findall(r'<book\s*rbr="\d+"\s*>.*?</book>', xml, flags=re.DOTALL)
title = '<title> Python Standard Library </title>'
# now search each <book>...</book> string looking for the title string:
for book in books:
if re.search(rf'{title}', book):
print(title)
print(book)
印刷:
<title> Python Standard Library </title>
<book rbr="2" >
<author> Fredrik Lundh </author>
<price currency="eur"> 50 </price>
<publisher> O'Reilly & Associates </publisher>
<year> 2001 </year>
<title> Python Standard Library </title>
</book>
推荐阅读
- python-3.x - 如何为值已经是字符串的变量进行转义?
- c# - 填充字典
- python - Python - 如何检查列表中的下一个值是否与上一个相同?
- azure - 如何在 Azure 中公开共享图像而不让自己面临黑白滥用/成本
- c# - .Net Core 3 / Entity Framework Core 将连接字符串放在 Appsettings.json 中不起作用
- applescript - AppleScript - 将文件夹从一个位置复制到另一个位置时排除某些文件
- python - 为什么我的代码绘制的图形只显示空白?
- r - 为什么 ggplot annotate 会抛出此警告:在 is.na(x) 中:is.na() 应用于“表达式”类型的非(列表或向量)
- grails - 使用 GORM,记录被保存到数据库中,但是当我尝试检索相同的实体时,它给出了保存的 id+1
- python - 关于显式删除 Python 框架的问题