解析SVG“路径"带有 C# 的元素 - 有没有库可以做到这一点? [英] Parsing SVG "path" elements with C# - are there libraries out there to do this?

查看:16
本文介绍了解析SVG“路径"带有 C# 的元素 - 有没有库可以做到这一点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 C# 编写一个程序,它本质上读取一个 SVG 文件,并对内容做一些有用的事情.我将使用的最复杂的数据是路径.它们采用如下形式:

I am writing a program in C# which essentially reads an SVG file, and does some useful things with the contents. The most complex data I will be working with are paths. They take forms such as this:

<path d="M5.4,3.806h6.336v43.276h20.738v5.256H5.4V3.806z"/>

在这种情况下,M、h、v、H、V 和 z 表示一些命令.在某种程度上,它们就像函数,它们后面的数字是参数.还有一些更复杂的:

In this case, the M, h, v, H, V, and z indicate some commands. In a way they are like functions, with the numbers following them being arguments. There are also some more complex ones:

<path d="M70.491,50.826c-2.232,1.152-6.913,2.304-12.817,2.304c-13.682,0-23.906-8.641-23.906-24.626
        c0-15.266,10.297-25.49,25.346-25.49c5.977,0,9.865,1.296,11.521,2.16l-1.584,5.112C66.747,9.134,63.363,8.27,59.33,8.27
        c-11.377,0-18.938,7.272-18.938,20.018c0,11.953,6.841,19.514,18.578,19.514c3.888,0,7.777-0.792,10.297-2.016L70.491,50.826z"/>

在本例中,c"命令后跟 6 个参数(在第一种情况下为 -2.232、1.152、-6.913、2.304、-12.817 和 2.304).你可以看到这会变得多么棘手.我的问题是:SO 社区是否知道任何将此类数据读入一些有用的 ADT 的现有库?

In this case, the "c" command is followed by 6 arguments (-2.232, 1.152, -6.913, 2.304, -12.817, and 2.304 in the first case). You can see how this can get tricky. My questions is this: is the SO community aware of any existing libraries that read such data into some useful ADTs?

在我开始编写所有代码并编写大量字符串解析函数之前,我真的不想重新发明轮子.此外,任何建议将不胜感激.我知道如何读取 XML 文档,这不是这里的问题.

Before I go off coding everything and writing a ton of string parsing functions, I'd really like to not re-invent the wheel. Also, any advice would be appreciated. I am aware of how to read an XML document, that isn't the issue here.

推荐答案

我不知道 c# 中的特定库,但是你可以从解析这种结构开始:

I don't know of specific libraries in c#, however you could start by parsing this kind of structure like this:

string path = "M5.4,3.806h6.336v43.276h20.738v5.256H5.4V3.806z";
string separators = @"(?=[MZLHVCSQTAmzlhvcsqta])"; // these letters are valid SVG
                             // commands. Whenever we find one, a new command is 
                             // starting. Let's split the string there.
var tokens = Regex.Split(path, separators).Where(t => !string.IsNullOrEmpty(t));

现在您有一个命令列表,后跟它们的参数.然后,您可以继续以相同的方式拆分参数.

now you have a list of commands followed by their arguments. You could then proceed to split the arguments in the same way.

你说参数可以用空格、逗号或减号分隔(与逗号和空格不同,它应该保留为参数的一部分),所以你可以使用另一个简单的正则表达式(注意我我不喜欢正则表达式,但在这种情况下,我认为它们增加了可读性).

You said the arguments can be separated by a space, a comma or a minus sign (which,unlike the comma and the whitespace, should remain part of the arguments), so you can use another simple regex (note that I'm no fan of regular expressions, but in this case I think they add to readability).

string argSeparators = @"[s,]|(?=-)"; // discard whitespace and comma but keep the -
var splitArgs = Regex
   .Split(remainingargs, argSeparators)
   .Where(t => !string.IsNullOrEmpty(t)); 

我会把它包装在一个 SVGCommand 类中,就像这样

I would wrap this in a SVGCommand class, like this

class SVGCommand
{
    public char command {get; private set;}
    public float[] arguments {get; private set;}

    public SVGCommand(char command, params float[] arguments)
    {
        this.command=command;
        this.arguments=arguments;
    }

    public static SVGCommand Parse(string SVGpathstring)
    {
        var cmd = SVGpathstring.Take(1).Single();
        string remainingargs = SVGpathstring.Substring(1);

        string argSeparators = @"[s,]|(?=-)";
        var splitArgs = Regex
            .Split(remainingargs, argSeparators)
            .Where(t => !string.IsNullOrEmpty(t));

        float[] floatArgs = splitArgs.Select(arg => float.Parse(arg)).ToArray();
        return new SVGCommand(cmd,floatArgs);
    }
}

现在一个简单的解释器"可能看起来像这样:

Now a simple "interpreter" could look something like this:

    string path = "M70.491,50.826c-2.232,1.152-6.913,2.304-12.817,2.304c-13.682,0-23.906-8.641-23.906-24.626" +
"c0-15.266,10.297-25.49,25.346-25.49c5.977,0,9.865,1.296,11.521,2.16l-1.584,5.112C66.747,9.134,63.363,8.27,59.33,8.27" +
"c-11.377,0-18.938,7.272-18.938,20.018c0,11.953,6.841,19.514,18.578,19.514c3.888,0,7.777-0.792,10.297-2.016L70.491,50.826z";
    string separators = @"(?=[A-Za-z])";
    var tokens = Regex.Split(path, separators).Where(t => !string.IsNullOrEmpty(t));

    // our "interpreter". Runs the list of commands and does something for each of them.
    foreach (string token in tokens){
                    // note that Parse could throw an exception
                    // if the path is not correct 
        SVGCommand c = SVGCommand.Parse(token);
        Console.WriteLine("doing something with command {0}", c.command);
    }

如果您需要做一些更复杂的事情,F# 可能更适合这项工作(并且可以与 C# 互操作).我并不是建议仅仅为了这个特定任务而学习 F#,我只是想我会提到它,以防你已经在研究其他东西.

If you need to do something more sophisticated, F# is probably better suited for the job (and is interoperable with C#). I'm not suggesting to learn F# just for this specific task, I just thought I'd mention it, in case you are already looking into it for something else.

这篇关于解析SVG“路径"带有 C# 的元素 - 有没有库可以做到这一点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆