【发布时间】:2020-12-03 12:50:03
【问题描述】:
我需要一个坚如磐石的正则表达式来尝试解决 Raphael.js parseStringPath 处理有关 Arc 路径命令和可能的其他命令的一些问题(SnapSVG 也继承了该问题)。你看,arcTo path 命令接受 7 个坐标和设置,但是某些字符串可能由于极端优化而格式错误,并且浏览器不会标记它们,而是正确呈现它们。检查Raphael.js demo here。
看看这个例子,我使用来自 Raphael.js 的 RegExp 和一个非常简单的例子,我自己的 RegExp 名为 incorrectReg,试图将 000 之类的字符串分解为 [0,@987654328 @,0] 或 011 转换为 [0,1,1]。
let spaces = "\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029",
pathValues = new RegExp(`(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[${spaces}]*,?[${spaces}]*`, `ig`),
incorectReg = new RegExp(`([${spaces}]*0(?=[a-z0-9])|([${spaces}]\\0)*0(?=[a-z0-9]*))`, `ig`); // THIS ONE
function action(){
let input = document.getElementById('input'),
output = document.getElementById('output'),
pathValue = input.getAttribute('d'),
segments = pathValue.replace(/([a-z])/gi,'|$1').split('|').filter(x=>x.trim()),
pathArray = []
segments.map(x=>{
let pathCommand = x[0],
pathParams = x.replace(pathCommand,'').trim()
pathArray.push( [pathCommand].concat(
pathParams.replace(',',' ')
.replace(pathValues,' $1 ')
.replace(incorectReg,'$1 ')
.split(' '))
.filter(x=>x)
);
})
output.setAttribute('d',pathArray.map(x=>x.join(' ')).join(''))
console.table(pathArray)
}
svg {max-width:49%}
<button onclick="action()">Extract</button>
<hr>
<svg viewBox="0 0 16 16">
<path id="input" d="M2,0a2 2 0 00,-2 2a2 2 0 002 2a.5.5 0 011 0z" stroke="red" stroke-width="1px" fill="none"></path>
</svg>
<svg viewBox="0 0 16 16">
<path id="output" d="M0 0" stroke="green" stroke-width="1" fill="none"></path>
</svg>
正如您在浏览器控制台中看到的,我们已经解决了000 组(这显然不是一个有效的数字、布尔值或任何特定的东西),我们只需要解决011 和11,其中所有这些组实际上都是一串布尔值。
同样,arcTo 路径命令适用于
arcTo -> ['A', rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y]
// str, float, float, float, boolean (0|1), boolean (0|1), float, float
我需要更好的incorrectReg RegExp 和组合解决方案来正确处理主要是arcTo 和其他类似情况。接受任何建议。
谢谢
【问题讨论】:
-
您是严格需要正则表达式,还是只想将
d属性拆分为组件?编写一个简单的解析器对 IMO 来说并不困难,您可以将其调整为所有这些“过度优化”(在小数分隔符和减号之前省略空格,省略 lineTo 命令......) -
我需要任何 RegExp + 其他解决方案的组合,我知道 fontello/svgpath.js 但那个人正在逐个字符地解析字符串,它没有失败,但我的代码完全支持拉斐尔,所以我需要一个综合解决方案。
-
“逐字符解析字符串”有什么问题?
-
也许
incorectReg = new RegExp(`(?<=[01${spaces}]+)([01])[${spaces}]*`, `g`);见 regex101.com/r/GVOHEy/1 并替换为完整匹配.replace(incorectReg,'$& ') -
@Thefourthbird 谢谢,这个正则表达式很好,但是这还不够,例如
1.874是一个布尔值(第 4 个参数)和一个浮点数(第 5 个参数),我可能会为 Raphael 发布一个 PR直接与我们的发现。再次感谢
标签: javascript regex svg raphael snap.svg