在 python 中用正则表达式解析一个 svg 相关的字符串
Parse a svg related string with regular expressions in python
我想在 svg 的路径元素中解析 d 属性命令。我想以一种有效的方式做到这一点。因此我决定使用正则表达式函数来避免使用多个循环。
我想要实现的是将命令字母及其数值放在一个元组中,并将所有这些元组存储在一个列表中,例如 [('M', '3', '18'), ('h', '10'), ...]
根据命令字母的不同,后面可以有一到六个数值。这些数值可以有一个点 ('.45') 或一个减号 ('-3') 或两者都有 ('-.55')。而且并不总是 space 将它们分开。例如'c -.55.45 0 1 '
.
我的做法:
这是我到目前为止尝试过的方法。我试图用 re.findall 方法将它们分开。但在那之后,我不得不用一个额外的循环将它们分组,那些带点的连接数值仍然连接在一起。此外,我想将替换方法集成到 findall 模式中。
# Just an extract of a d command
d = 'M20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16'
commands = re.findall("[mMzZlLhHvVcCsSqGtTaA]|[0-99\-.]+", d.replace("-", " -"))
#output: ['M', '20', '3', 'H', '4', 'c', '-.55', '0', '-1', '.45', '-1', '1', 'v', '6', 'c', '0', '.55.45', '1', '1', '1', 'h', '16']
#goal: [('M', '20', '3'), ('H', '4'), ('c', '-.55', '0', '-1', '.45', '-1', '1'), ('v', '6'), ('c', '0', '.55', '.45', '1', '1', '1'), ('h', '16')]
那些虚线连接的数值看起来很简单。我只是把它们按点分开。但这是不可能的,因为我可能会得到像“1.55”这样的值。但是随后这个值用 space 与另一个值 ('.55 1.45') 分隔。由于我在这些正则表达式模式上遇到了困难,如果有人有解决方案或者至少可以指导我朝着正确的方向前进,那就太棒了。
如果我遗漏了什么或者您需要更多信息,请告诉我,我会提供。提前致谢!
如果只能有零到六个参数,使用一个正则表达式方法的最佳方法是使用
re.findall("([mMzZlLhHvVcCsSqGtTaA])(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?", d)
见regex demo。 (?:\s*(-?\d*\.?\d+))?
模式重复 6 次以匹配 1 到 6 个参数并将它们中的每一个捕获到它自己的组中。 (?:...)?
是可选的非捕获组,\s*(-?\d*\.?\d+)
匹配 0+ 个空格 (\s*
),(-?\d*\.?\d+)
将可选的 -
(-?
), 0+ 位 (\d*
), 一个可选的点 (\.?
) 和 1+ 位 (\d+
).
参见Python demo:
import re
d = 'M0 0h24v24H0z'
commands = re.findall(r"([mMzZlLhHvVcCsSqGtTaA])(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?", d)
print([tuple(list(filter(None, x))) for x in commands])
# => [('M', '0', '0'), ('h', '24'), ('v', '24'), ('H', '0'), ('z',)]
我想在 svg 的路径元素中解析 d 属性命令。我想以一种有效的方式做到这一点。因此我决定使用正则表达式函数来避免使用多个循环。
我想要实现的是将命令字母及其数值放在一个元组中,并将所有这些元组存储在一个列表中,例如 [('M', '3', '18'), ('h', '10'), ...]
根据命令字母的不同,后面可以有一到六个数值。这些数值可以有一个点 ('.45') 或一个减号 ('-3') 或两者都有 ('-.55')。而且并不总是 space 将它们分开。例如'c -.55.45 0 1 '
.
我的做法:
这是我到目前为止尝试过的方法。我试图用 re.findall 方法将它们分开。但在那之后,我不得不用一个额外的循环将它们分组,那些带点的连接数值仍然连接在一起。此外,我想将替换方法集成到 findall 模式中。
# Just an extract of a d command
d = 'M20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16'
commands = re.findall("[mMzZlLhHvVcCsSqGtTaA]|[0-99\-.]+", d.replace("-", " -"))
#output: ['M', '20', '3', 'H', '4', 'c', '-.55', '0', '-1', '.45', '-1', '1', 'v', '6', 'c', '0', '.55.45', '1', '1', '1', 'h', '16']
#goal: [('M', '20', '3'), ('H', '4'), ('c', '-.55', '0', '-1', '.45', '-1', '1'), ('v', '6'), ('c', '0', '.55', '.45', '1', '1', '1'), ('h', '16')]
那些虚线连接的数值看起来很简单。我只是把它们按点分开。但这是不可能的,因为我可能会得到像“1.55”这样的值。但是随后这个值用 space 与另一个值 ('.55 1.45') 分隔。由于我在这些正则表达式模式上遇到了困难,如果有人有解决方案或者至少可以指导我朝着正确的方向前进,那就太棒了。
如果我遗漏了什么或者您需要更多信息,请告诉我,我会提供。提前致谢!
如果只能有零到六个参数,使用一个正则表达式方法的最佳方法是使用
re.findall("([mMzZlLhHvVcCsSqGtTaA])(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?", d)
见regex demo。 (?:\s*(-?\d*\.?\d+))?
模式重复 6 次以匹配 1 到 6 个参数并将它们中的每一个捕获到它自己的组中。 (?:...)?
是可选的非捕获组,\s*(-?\d*\.?\d+)
匹配 0+ 个空格 (\s*
),(-?\d*\.?\d+)
将可选的 -
(-?
), 0+ 位 (\d*
), 一个可选的点 (\.?
) 和 1+ 位 (\d+
).
参见Python demo:
import re
d = 'M0 0h24v24H0z'
commands = re.findall(r"([mMzZlLhHvVcCsSqGtTaA])(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?", d)
print([tuple(list(filter(None, x))) for x in commands])
# => [('M', '0', '0'), ('h', '24'), ('v', '24'), ('H', '0'), ('z',)]