我有以下文字:
<clipPath id="p54dfe3d8fa">
<path d="M 112.176 307.8
L 112.176 307.8
L 174.672 270
L 241.632 171.72
L 304.128 58.32
L 380.016 171.72
L 442.512 217.08
L 491.616 141.48
L 491.616 307.8
z
"/>
</clipPath>
<clipPath id="p27c84a8b3c">
<rect height="302.4" width="446.4" x="72.0" y="43.2"/>
</clipPath>
我需要抓住这一部分:
d="M 112.176 307.8
L 112.176 307.8
L 174.672 270
L 241.632 171.72
L 304.128 58.32
L 380.016 171.72
L 442.512 217.08
L 491.616 141.48
L 491.616 307.8
z
"
我需要用其他东西替换这部分。我能够抓住整个<clipPath ...><path d="[code i want]"/>
,但这对我没有帮助,因为我无法覆盖<clipPath>
元素中的ID。
请注意,还有其他<clipPath>
元素我不想触及。我只想更改<path>
元素中的<clipPath>
元素。
我认为答案与在clipPath元素之前选择所有内容并在Path部分结束时有关。任何帮助都将完全受到赞赏。
我一直在使用http://pythex.org/寻求帮助,并且还看到了奇怪的行为(与多行和空格有关),这些行为与python 3.x代码之间的行为不同。
以下是我尝试过的一些事情:
reg = r'(<clipPath.* id=".*".*>)'
reg = re.compile(r'(<clipPath.* id=".*".*>\s*<path.*d="(.*\n)+")')
reg = re.compile(r'((?<!<clipPath).* id=".*".*>\s*<path.*d="(.*\n)+")')
g = reg.search(text)
g
答案 0 :(得分:3)
正则表达式从不解析xml的正确方法。
这是一个简单的独立示例,它使用lxml
:
from lxml import etree
text="""<clipPath id="p54dfe3d8fa">
<path d="M 112.176 307.8
L 112.176 307.8
L 174.672 270
L 241.632 171.72
L 304.128 58.32
L 380.016 171.72
L 442.512 217.08
L 491.616 141.48
L 491.616 307.8
z
"/>
</clipPath>
<clipPath id="p27c84a8b3c">
<rect height="302.4" width="446.4" x="72.0" y="43.2"/>
</clipPath>"""
# This creates <metrics>
root = etree.XML("<X>"+text+"</X>")
p = root.find(".//path")
print(p.get("d"))
结果:
M 112.176 307.8 L 112.176 307.8 L 174.672 270 L 241.632 171.72 L 304.128 58.32 L 380.016 171.72 L 442.512 217.08 L 491.616 141.48 L 491.616 307.8 z
d
属性现在我正在更改d
的文本并将其转储:
p.set("d","[new text]")
print(etree.tostring(root))
现在输出如下:
...
<path d="[new text]"/>\n
...
仍然,快速和肮脏,可能对多个path
节点不健壮,但可以使用您提供的代码段(我不是xml专家,只是摸索)
split
:
text.split(' d="')[1].split('"/>')[0]
在d分隔符之后取第二部分,然后在/>
分隔符之后取第一部分。保留多行格式。
答案 1 :(得分:2)
TL; DR: r'<clipPath.* id="[a-zA-Z0-9]+".*>\s*<path.*d=("(?:.*\n)+?")'
让我们打破这个......
您从:r'(<clipPath.* id=".*".*>\s*<path.*d="(.*\n)+")'
开始,它将整个捕获模式包含在一个组中,因此整个元素将在匹配对象中捕获。让我们取出那些括号:r'<clipPath.* id=".*".*>\s*<path.*d="(.*\n)+"'
接下来你似乎经常使用.*
,这可能是危险的,因为它是盲目和贪婪的。对于clipPath id,如果您知道id始终是字母数字,则更好的解决方案可能是r'<clipPath.* id="[a-zA-Z0-9]+".*>\s*<path.*d="(.*\n)+"'
最后,让我们来看看你真正想要捕捉的内容。您的示例显示您要捕获引号,所以让我们在捕获组中找到它们:...*d=("(.*\n)+")
。这给我们留下了一个奇怪的嵌套组情况,所以让我们让内部组不捕获:...*d=("(?:.*\n)+")
。
现在我们正在捕捉你想要的东西,但是我们仍然有问题......如果有多个元素满足这些标准怎么办? +
...*d=("(.*\n)+")
中的+
的贪婪匹配将在中间捕获。我们在这里可以做的是通过?
:...*d=("(?:.*\n)+?")
跟随r'<clipPath.* id="[a-zA-Z0-9]+".*>\s*<path.*d=("(?:.*\n)+?")'
非贪婪。
把所有这些东西放在一起:
SELECT Message.Subject
FROM Message
JOIN To IN Message.To
WHERE To.Address = "you@company.com"
SELECT Message.Subject
FROM Message
JOIN To IN Message.Cc
WHERE Cc.Address = "you@company.com"
答案 2 :(得分:1)
基于xml
的解决方案,用于修改路径。
import xml.dom.minidom
# Open XML document using minidom parser
DOMTree = xml.dom.minidom.parseString('<X>' + my_xml + '</X>')
collection = DOMTree.documentElement
for clip_path in collection.getElementsByTagName("clipPath"):
paths = clip_path.getElementsByTagName('path')
for path in paths:
path.setAttribute('d', '[code i want]')
print DOMTree.toxml()
使用的数据:
my_xml = """
<clipPath id="p54dfe3d8fa">
<path d="M 112.176 307.8
L 112.176 307.8
L 174.672 270
L 241.632 171.72
L 304.128 58.32
L 380.016 171.72
L 442.512 217.08
L 491.616 141.48
L 491.616 307.8
z
"/>
</clipPath>
<clipPath id="p27c84a8b3c">
<rect height="302.4" width="446.4" x="72.0" y="43.2"/>
</clipPath>
"""