【问题标题】:Parse a svg related string with regular expressions in python在 python 中使用正则表达式解析 svg 相关字符串
【发布时间】:2020-05-09 10:22:57
【问题描述】:

我想解析 svg 的路径元素中的 d 属性命令。我想以一种有效的方式做到这一点。因此,我决定使用正则表达式函数来避免使用多个循环。

我想要实现的是将命令字母及其数值放在一个元组中,并将所有这些元组存储在一个列表中,例如[('M', '3', '18'), ('h', '10'), ...]

根据命令字母的不同,后面可以有 1 到 6 个数值。这些数值可以有一个点('.45')或一个减号('-3')或两者都有('-.55')。并且并不总是有空格分隔它们。例如'c -.55.45 0 1 '.

我的方法:

这是我到目前为止所尝试的。我试图用 re.findall 方法将它们分开。但在那之后,我不得不用一个额外的循环对它们进行分组,并且那些带有点的连接数值仍然是连接的。此外,我想将 replace 方法集成到 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”这样的值。但随后这个值用空格分隔到另一个值('.55 1.45')。由于我在使用这些正则表达式模式时遇到了困难,如果有人有解决方案或者至少可以引导我走向正确的方向,那就太棒了。

如果我遗漏了什么或者您需要更多信息,请告诉我,我会提供。提前谢谢!

【问题讨论】:

  • 如果可以有 1 到 6 个参数,使用一个正则表达式方法的最佳方法是使用 re.findall("([mMzZlLhHvVcCsSqGtTaA])\s*(-?\d*\.?\d+)(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?(?:\s*(-?\d*\.?\d+))?", d)。但是你最终会因为缺少参数而得到空项目。见ideone.com/MrA8UQ。而且您将无法使用单个正则表达式摆脱它们,您需要使用另一个列表理解进行后处理。
  • @Wiktor Stribiżew 谢谢!这对我有很大帮助。我使用过滤器对列表进行后期处理,以消除那些空字符串。但是,如果我解析M0 0h24v24H0z 这个例子,z 就会丢失。如何修改模式?
  • 那是因为你所有的论点似乎都是可选的,我以为至少有1个,你说可以有1到6个。所以,使用ideone.com/lWDjW4
  • z 和 Z 没有参数。带参数的命令通常可以重复参数,因此 M 后面可以有无数对参数。
  • 您似乎没有考虑过路径有多复杂,例如a9.62 9.62 0 110-.05 是具有 6 值的弧。 110-.05 实际上有 1 1 0 -0.05

标签: python python-3.x regex svg python-re


【解决方案1】:

如果只能有 0 到 6 个参数,则使用一个正则表达式方法的最佳方法是使用

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',)]

【讨论】:

    猜你喜欢
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    相关资源
    最近更新 更多