我有这种形式的路径定义(例子):
<path d="M 20 30 L 20 20 20 40 40 40"/>
在Lua中,成为:
"M 20 30 L 20 20 20 40 40 40"
我怎样才能在纯Lua中解析它以获得类似的东西:
{'M', 20, 30, 'L', 20, 20, 20, 40, 40, 40 }
或者,完美:
{{'M', 20, 30}, {'L', 20, 20}, {'L', 20, 40}, {'L', 40, 40}}
Lua模式是否具备此类功能?
编辑: 我想要涵盖所有有效的SVG路径,或者至少包含Inkscape生成的路径。 specification inkscape-generated path
答案 0 :(得分:1)
local path = 'M 20 30 L 20 20 20 40 40 40'
local s, t = '', {}
for c, x, y in path:gmatch'(%a?)%s*(%d+)%s*(%d+)' do
s = (s..c):sub(-1)
t[#t+1] = {s, tonumber(x), tonumber(y)}
end
-- Now t == {{'M', 20, 30}, {'L', 20, 20}, {'L', 20, 40}, {'L', 40, 40}}
答案 1 :(得分:1)
不是直接的,你当然需要一个简化的解析器。
好奇心让我变得更好,虽然我常常不喜欢“为我做这件事”的帖子
--- Parse svg `path` attribute into 2-D array
function parsePath(input)
local output, line = {}, {};
output[#output+1] = line;
input = input:gsub("([^%s,;])([%a])", "%1 %2"); -- Convert "100D" to "100 D"
input = input:gsub("([%a])([^%s,;])", "%1 %2"); -- Convert "D100" to "D 100"
for v in input:gmatch("([^%s,;]+)") do
if not tonumber(v) and #line > 0 then
line = {};
output[#output+1] = line;
end
line[#line+1] = v;
end
return output;
end
-- Test output
local input = 'M20 30L20 20,20 40;40 40 X1 2 3 12.8z';
local r = parsePath(input);
for i=1, #r do
print("{ "..table.concat(r[i], ", ").." }");
end
由于Inkscape似乎总是在指令和数字之间放置一个空格,如果你只解析Inkscape生成的文件,你可以省去两个gsub行。
该函数还抛弃了大多数随机字符,Inkscape喜欢将其置于路径定义中,但如果确实想要读取符合该路径的所有路径定义,则可能会有一些细节需要解决。标准。
SVG标准声明Superfluous white space and separators such as commas can be eliminated
,但是在查看BNF表示法时,我找不到除空格和逗号之外的任何其他分隔符。
所以你可以将第二个正则表达式改为"([^%a%d%.eE-]+)"
。但我认为以下功能更适合:
function parsePath(input)
local out = {};
for instr, vals in input:gmatch("([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)") do
local line = { instr };
for v in vals:gmatch("([+-]?[%deE.]+)") do
line[#line+1] = v;
end
out[#out+1] = line;
end
return out;
end
-- Test output
local input = 'M20-30L20,20,20X40,40-40H1,2E1.7 1.8e22,3,12.8z';
local r = parsePath(input);
for i=1, #r do
print("{ "..table.concat(r[i], ", ").." }");
end
这个函数非常宽松,因为它允许遗漏任何不必要的空格,并且不会验证任何语义,除了它会在第一个字母不是e
或{{1之前丢弃任何数据}}
它也会默默地忽略任何不匹配的数据。
如果您只想匹配现有说明,可以将模式E
替换为([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)
。但是这会导致不存在的指令的所有值都被添加到前一条指令中,因此我认为这不是一个好主意,最好解析一个超集并稍后在语义上抛出错误。