もちろん、直接ではなく、単純化されたパーサーが必要になります。
好奇心に負けたけど、普段は「Do this work for me」の投稿は嫌い
--- 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 によって生成されたファイルのみを解析する場合は、2 つの gsub 行を省略できます。
この関数は、Inkscape がパス定義に入れたいランダムな文字のほとんどを破棄しますが、標準に準拠するすべてのパス定義を本当に読みたい場合は、詳細を解決する必要があるかもしれません。
SVG 標準Superfluous white space and separators such as commas can be eliminated
には と記載されていますが、BNF 表記を見てみると、空白とコンマ以外の区切り文字が見つかりませんでした。
したがって、おそらく 2 番目の正規表現を に変更できます"([^%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
この関数は、不必要な空白を省略できるという点で非常に寛大であり、 orでない最初の文字の前のデータを破棄する以外のセマンティクスを検証しませんE
。
また、一致しないデータは黙って無視します。
既存の命令のみを一致させたい場合は、パターン([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)
を に置き換えることができます([MmZzLlHhVvCcSsQqTtAa])([^MmZzLlHhVvCcSsQqTtAa]*)
。ただし、これにより、存在しない命令のすべての値が前の命令に追加されるため、これは良い考えではないと思います。スーパーセットを解析し、後でセマンティクスにエラーをスローすることをお勧めします。