使用Python正则表达式高效解析SVG路径元素的d属性命令
我之前做SVG路径解析的时候正好踩过类似的坑,你的思路没问题,核心就是要先正确拆分所有合法的命令和数值,再把它们按命令分组。之前的问题出在数值匹配的正则不对,导致连写的小数(比如.55.45)被当成了一个整体。
解决方案步骤
1. 先正确拆分所有Token(命令+单个数值)
首先要写一个能精准匹配SVG合法数值的正则,同时匹配所有SVG路径命令字母。合法数值的规则是:
- 可选负号开头
- 可以是整数(如
123、-4) - 可以是小数(如
.55、1.67、-.89)
对应的正则表达式是:
token_pattern = r'[mMzZlLhHvVcCsSqQrRtTaA]|-?\d*\.?\d+'
这个正则会把每个命令字母和每个单独的数值都拆分成独立的token,完美解决.55.45这类连写数值的拆分问题。
2. 将Token按命令分组
拆分出所有token后,我们只需要遍历这些token,把每个命令和它后面跟随的所有数值打包成元组,直到遇到下一个命令为止。
完整代码示例
import re def parse_svg_d(d): # 匹配SVG路径命令和合法数值 token_pattern = r'[mMzZlLhHvVcCsSqQrRtTaA]|-?\d*\.?\d+' tokens = re.findall(token_pattern, d) if not tokens: return [] parsed_commands = [] current_command = tokens[0] current_values = [] for token in tokens[1:]: # 判断当前token是命令还是数值 if re.fullmatch(r'[mMzZlLhHvVcCsSqQrRtTaA]', token): # 遇到新命令,把之前的命令+数值存入结果 parsed_commands.append((current_command, *current_values)) current_command = token current_values = [] else: # 是数值,加入当前命令的数值列表 current_values.append(token) # 处理最后一组命令 parsed_commands.append((current_command, *current_values)) return parsed_commands # 测试你的示例d属性 d = 'M20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16' result = parse_svg_d(d) print(result)
输出结果
[('M', '20', '3'), ('H', '4'), ('c', '-.55', '0', '-1', '.45', '-1', '1'), ('v', '6'), ('c', '0', '.55', '.45', '1', '1', '1'), ('h', '16')]
为什么这个方法可行?
- 数值正则
-?\d*\.?\d+确保了每个合法的数值都会被单独匹配,不会把连写的小数当成一个整体; - 遍历分组的逻辑简单清晰,还能自动处理
Z/z这类不带数值的命令(会生成('Z',)这样的元组),兼容性很好。
如果你想尝试用单个正则直接匹配命令+数值组,理论上可以,但需要针对每个命令的数值数量写复杂的分支规则,维护起来非常麻烦,不如这种拆分+分组的方式直观可靠。
内容的提问来源于stack exchange,提问作者MisterNox
相关产品推荐
相关产品推荐

