鱼C论坛

 找回密码
 立即注册
查看: 1991|回复: 14

python re 正则匹配问题

[复制链接]
发表于 2023-7-12 12:31:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
现有xml文档如下:
<root>
  <a>
    <b>字0</b>
  </a>
  <a>
    <b>字1</b>
  </a>
  <a>
    <b>字2</b>
  </a>
</root>

现在我需要用re正则表达式匹配:
<a>
  <b>字1</b>
</a>

无论我如何尝试,都只能匹配到下面的情况:
<a>
  <b>字0</b>
</a>
<a>
  <b>字1</b>
</a>

使用的re pattern为"<a[\s\S]*?字1[\s\S]*?a>"

请问能有什么方法?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-12 12:31:11 | 显示全部楼层
使用正则表达式来解析 XML 是一个常见的问题。然而,由于 XML 是一种结构化的数据格式,正则表达式并不是最适合解析它的工具。推荐使用专门处理 XML 的库,如 xml.etree.ElementTreelxml

以下是使用 xml.etree.ElementTree 模块解析 XML 并找到目标节点的示例代码:
import xml.etree.ElementTree as ET# 定义 XML 数据data = "<root><a><b>字0</b></a><a><b>字1</b></a><a><b>字2</b></a></root>"# 解析 XMLroot = ET.fromstring(data)# 使用 XPath 表达式查找目标节点target_node = root.find(".//a[b='字1']")# 输出结果if target_node is not None:    print(ET.tostring(target_node, encoding="unicode"))else:    print("未找到匹配的节点")
在上述代码中,我们使用 ET.fromstring() 函数将 XML 字符串转换为 Element 对象。然后,使用 find() 方法和 XPath 表达式 .//a[b='字1'] 找到匹配的目标节点。最后,使用 ET.tostring() 函数将节点转换回字符串并打印输出。

请注意,XPath 表达式 .//a[b='字1'] 表示在整个 XML 树中查找包含 <b> 元素且其文本内容为 "字1"<a> 元素。

使用专门的 XML 解析库可以更方便、可靠地处理复杂的 XML 结构,而不需要自己编写复杂的正则表达式。这样可以更好地保持代码的可读性和可维护性。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 12:33:32 | 显示全部楼层
你要匹配啥?
还有<a[\s\S]*?字1[\s\S]*?a>,里面不是有“字1”了吗,python会一直往后匹配
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 12:38:06 | 显示全部楼层
在 Python 中,对于解析 XML 文档,通常推荐使用专门的 XML 解析库,例如  xml.etree.ElementTree  或  lxml ,而不是使用正则表达式。这是因为 XML 文档的结构可能非常复杂,并且使用正则表达式可能会导致很多意外的匹配。

然而,如果你还是想继续使用正则表达式,可以试试以下这个正则表达式:
re.findall(r"<a>\s*<b>字1</b>\s*</a>", your_xml_string)

这个正则表达式的核心思想是利用  \s*  来匹配任意数量的空白字符(包括空格,制表符,换行符等)。这样可以确保即使  <b>  标签前后有空格或者换行,也能正确地匹配。

但是我还是强烈建议你使用 XML 解析库来处理这类问题,这样更为稳定和有效。下面是一个使用  xml.etree.ElementTree  的例子:
import xml.etree.ElementTree as ET

data = """
<root>
  <a>
    <b>字0</b>
  </a>
  <a>
    <b>字1</b>
  </a>
  <a>
    <b>字2</b>
  </a>
</root>
"""

root = ET.fromstring(data)

for a in root.findall('a'):
    b = a.find('b')
    if b is not None and b.text == '字1':
        print(ET.tostring(a).decode())

这段代码首先解析 XML 数据,然后查找所有的  <a>  元素,对于每一个  <a>  元素,再查找其下的  <b>  元素,并检查其内容是否为 '字1'。如果是,就打印出这个  <a>  元素。这种方法的优点是能够正确地处理复杂的 XML 数据,并且更加灵活和可控。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-12 12:41:25 | 显示全部楼层
歌者文明清理员 发表于 2023-7-12 12:33
你要匹配啥?
还有,里面不是有“字1”了吗,python会一直往后匹配

我只需要包含"字1"的a标签,但是匹配结果总是给了不止一个a标签,
我自己是知道原因的:
    匹配从头部开始匹配  <a
    然后往后匹配  [\s\S]*?  即任何字符
    直到碰见特殊设定的字符  字1
    然后继续往后匹配  [\s\S]*?
    直到最后匹配到  a>  的关闭标签
问题就出在第一步
匹配开始标签时的位置就错了,导致第二步时直接匹配了一个完整的 a 标签在里面
我不知道该怎么解决
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 12:44:59 | 显示全部楼层
未有名 发表于 2023-7-12 12:41
我只需要包含"字1"的a标签,但是匹配结果总是给了不止一个a标签,
我自己是知道原因的:
    匹配从头部 ...

你可以尝试使用非贪婪匹配模式,将 <a> 和 </a> 之间的内容匹配为一个分组,并在该分组中继续匹配 <b>字1</b>。以下是修改后的正则表达式示例:
<a[\s\S]*?<b>字1<\/b>[\s\S]*?<\/a>

这样修改后的正则表达式会选择最短的匹配,确保只匹配到 <a> 和 <b>字1</b> 在同一个 <a> 标签内的情况。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-12 12:50:34 | 显示全部楼层
歌者文明清理员 发表于 2023-7-12 12:44
你可以尝试使用非贪婪匹配模式,将  和  之间的内容匹配为一个分组,并在该分组中继续匹配 字1。以下是修 ...

没有用的
匹配会从包含"字0"的 a 标签头开始
直到匹配到"字1",然后最后再去匹配 a 的关闭标签
在<a 和 字1 之间的匹配非贪婪也没用
就是没办法跳过包含"字0"的 a 标签
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 12:52:45 | 显示全部楼层
本帖最后由 歌者文明清理员 于 2023-7-12 12:53 编辑
未有名 发表于 2023-7-12 12:50
没有用的
匹配会从包含"字0"的 a 标签头开始
直到匹配到"字1",然后最后再去匹配 a 的关闭标签

import re
xml  ='''<root>
  <a>
    <b>字0</b>
  </a>
  <a>
    <b>字1</b>
  </a>
  <a>
    <b>字2</b>
  </a>
</root>'''
match = re.match("<a.*?</a>.*?(<a.*?字1.*?</a>)", xml)
print(match.group(1))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 12:58:25 | 显示全部楼层
这种不要用正则了,用bs4(非gpt):
from bs4 import BeautifulSoup
xml = '''...'''
soup = BeautifulSoup(xml, "lxml")
tags = soup.find_all("a")
target = None
for tag in tags:
    if "字1" in str(tag):
        target = tag
        break
print(str(target))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 13:13:23 | 显示全部楼层
还有一种
你可以尝试使用非贪婪模式匹配的方式来解决这个问题。在正则表达式中,非贪婪模式通过在匹配符号后面添加一个问号(?)来实现。

在你的例子中,你可以将正则表达式修改为"<a[\s\S]*?字1[\s\S]*?</a>"。这样修改后,正则表达式会匹配最短的满足条件的字符串,即你所期望的结果。

下面是修改后的代码示例:

```python
import re

xml = '''
<root>
  <a>
    <b>字0</b>
  </a>
  <a>
    <b>字1</b>
  </a>
  <a>
    <b>字2</b>
  </a>
</root>
'''

pattern = r"<a[\s\S]*?字1[\s\S]*?</a>"
result = re.findall(pattern, xml)
print(result)
```

输出结果为:
['<a>\n    <b>字1</b>\n  </a>']

这样你就可以得到你所需的匹配结果了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-12 13:27:46 | 显示全部楼层

其实我的真实情况是,我不能使用python
只有使用notepad--自带的正则表达式去实现匹配替换
谢谢你的回答
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 13:31:00 | 显示全部楼层
未有名 发表于 2023-7-12 13:27
其实我的真实情况是,我不能使用python
只有使用notepad--自带的正则表达式去实现匹配替换
谢谢你的回 ...

那你就去匹配<a[\s\S]*?字1[\s\S]*?</a>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-12 13:36:05 | 显示全部楼层

这个答案不对
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-12 13:36:45 | 显示全部楼层
歌者文明清理员 发表于 2023-7-12 13:13
还有一种
你可以尝试使用非贪婪模式匹配的方式来解决这个问题。在正则表达式中,非贪婪模式通过在匹配符号 ...

你这个给的python代码跑出来的结果是
['<a>\n    <b>字0</b>\n  </a>\n  <a>\n    <b>字1</b>\n  </a>']
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-12 13:43:47 | 显示全部楼层
未有名 发表于 2023-7-12 13:36
你这个给的python代码跑出来的结果是
['\n    字0\n  \n  \n    字1\n  ']

属实做不到
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-22 13:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表