views:

768

answers:

2

Hi, i need to parse some paths of an SVG file, they are simple lines. When retrieving the data i end up with this string:

m 0,666.6479 254.28571,0

According to SVG specifications m denotes a new current point then the following 2 numbers are the position and the laters are relative positions to the first one.

So that would create a line from point (0, 666.6479) to (254.28, 666.64)

How can i parse that in Objective-C so i can end up with those 2 CGPoints or more if there were?

i know that if it finds an m, the following 2 comma separated numbers should be my first point and after each space there are 2 comma separated numbers that i should sum to the current point to get the next one.

What i don't know if how to parse this correctly.

Thanks!

+1  A: 

I would use C directly, as:

const char *str = [myString UTF8String];

while(*str)
{
    switch(*str)
    {
        case 'm':
            state = START;
            break;
        case ' ':
            if(state == START) /* we are just after the m */
            {
                state = POINT;
                point = 0;
                break;
            }
            else if(state == POINT)
            {
                if(sscanf(str, "%f,%f", &x, &y) != 2)
                    /* handle error; */
                /* save point somewhere */
                point++;
            }
            break;
    }
    str++;
}

Please note that I just written that in the edit box, just take it as an example.

The other approach is to use NSScanner, but I feel like the above approach is simpler as per your requirements.

Thanks, that worked great!
pabloruiz55
Just note that this parser is not robust at all. You might want to eat any extra whitespace and separate the two float parsing, as it might (I don't know the SVG specs) be written 3.4 , 2.3.
Also, as per eating whitespaces, you might consider strtod serie of functions, as they will ignore trailing spaces.
A: 

The "m" command takes only two parameters: the x and y coordinates. But whereas "M" (uppercase) takes absolute coordinates, "m" (lowercase) takes relative coordinates. Thus, if your current coordinates (before the "m" command") were (100,100), the relative move in your example will bring them to (100, 766.6479).

The fact that there is no new command letter after these two coordinates means that the next command is also a relative move, so that brings you to (354.28571, 766.6479).

From the SVG 1.1 spec:

The command letter can be eliminated on subsequent commands if the same command is used multiple times in a row (e.g., you can drop the second "L" in "M 100 200 L 200 100 L -100 -200" and use "M 100 200 L 200 100 -100 -200" instead).

You can use NSScanner to parse decimal numbers:

NSScanner *scanner = [NSScanner scannerWithString:aString];
float num = 0;
BOOL success = [scanner scanFloat:&num];
if (succes) {
// Do something
}
else {
// Throw exception
}

Correctly parsing SVG files is a bit tricky, because the spec is pretty relaxed about how data is formatted. If you want to write a parser that is robust enough to accept input from any source (Illustrator, InkScape...), I would recommend having a close look at the Batik project's microsyntax parsers. (Although you can get something decent working that might cover your needs without anything near Batik's complexity.)

Felixyz