Extract Coordinates from a String
Given a string such as "123,456 27.5,-50 500.0,-500.0", I needed to extract the coordinate point-pairs. I wrote a simple parser to do this. This solution is more stable, robust and maintainable than an uglier brute-force method.
This code is for the Cobra programming language, however it should be easy to port to your language of choice.
Program
Var
parseSvgPoints_index0: Integer
parseSvgPoints_index1: Integer
parseSvgPoints_string: String
parseSvgPoints_strlen: Integer
parseSvgPoints_lexeme: String
Function ParseSvgPoints(s: String) : Boolean
Var
i: Integer
c: String
token: Integer
active: Integer
point1, point2: Real
Begin
InitSvgPointsToken(s)
active = -1
Repeat
token = GetNextSvgPointsToken()
Case token of
1: // Comma
Case active of
-1: // Error (fail silently)
1: active=2
2: // Error (fail silently)
EndCase
2: // Float
Case active of
-1: active = 1; point1 = ToReal(parseSvgPoints_lexeme)
1: // Error (fail silently)
2: active=-1; point2 = ToReal(parseSvgPoints_lexeme);
MessageBox("Points: "+point1+", "+point2)
// Do things with your points here!
EndCase
-1:
EndCase
Until token = -1
End
Function InitSvgPointsToken(s: String) : Boolean
Begin
parseSvgPoints_index0 = 0
parseSvgPoints_index1 = 0
parseSvgPoints_string = s
parseSvgPoints_strlen = Length(s)
parseSvgPoints_lexeme = ""
End
Function GetNextSvgPointsToken() : Integer
(*
Result:
-1: End of Stream / error
1: Comma
2: Float value
*)
Var
l: Integer
c: String
Begin
parseSvgPoints_index0 = parseSvgPoints_index1
result = -1
// Skip through whitespace
While (TRUE)
c = Mid(parseSvgPoints_string, parseSvgPoints_index0+1, 1)
If Svg_CharIsWhiteSpace(c) = FALSE then break
Inc(parseSvgPoints_index0)
If parseSvgPoints_index0 >= parseSvgPoints_strlen then break
Wend
parseSvgPoints_index1 = parseSvgPoints_index0
// Scan through until a delimiter is met, incrementing index1
While (TRUE)
c = Mid(parseSvgPoints_string, parseSvgPoints_index1+1, 1)
If Svg_CharIsPointsDelim(c) then break
Inc(parseSvgPoints_index1)
If parseSvgPoints_index1 >= parseSvgPoints_strlen then break
Wend
If (parseSvgPoints_index1 - parseSvgPoints_index0) = 0 then Inc(parseSvgPoints_index1)
// Lexeme Isolatted, lies between index0 and index1
parseSvgPoints_lexeme = Mid(parseSvgPoints_string, parseSvgPoints_index0+1, (parseSvgPoints_index1-parseSvgPoints_index0))
result = -1
Conditions
(parseSvgPoints_lexeme = ','): result = 1
(Svg_StringIsFloat(parseSvgPoints_lexeme)): result = 2
EndConditions
End
Function Svg_CharIsPointsDelim(c: String) : Boolean
Begin
result = FALSE
If (c = ',') then result = TRUE ; exit
result = Svg_CharIsWhitespace(c)
End
Function Svg_CharIsNumeric(c: String) : Boolean
Var
a: Integer
Begin
a = Asc(c)
If (a >= 48) and (a <= 57) then result = TRUE else result = FALSE
End
Function Svg_CharIsWhitespace(c: String) : Boolean
Var
a: Integer
Begin
a = Asc(c) // Tab = 9, Space = 32, Newline = 10
If (a = 9) or (a = 32) or (a = 10) then result = TRUE else result = FALSE
End
Function Svg_StringIsFloat(s: String) : Boolean ; export
Var
l, i: Integer
radix: Integer = 0
c: String
Begin
result = FALSE
l = Length(s)
If l < 1 then exit
For i = 1 to l
c = Mid(s, i, 1)
If Not (Svg_CharIsNumeric(c) or (c = '-') or (c = '.')) then exit
If (i <> 1) and (c = '-') then exit
If (c = '.') then
Inc(radix)
If i = l then exit
Endif
If radix > 1 then exit
Next
result = TRUE
End
Begin
ParseSvgPoints("123,456 27.5,-50 500.0,-500.0")
End
Var
parseSvgPoints_index0: Integer
parseSvgPoints_index1: Integer
parseSvgPoints_string: String
parseSvgPoints_strlen: Integer
parseSvgPoints_lexeme: String
Function ParseSvgPoints(s: String) : Boolean
Var
i: Integer
c: String
token: Integer
active: Integer
point1, point2: Real
Begin
InitSvgPointsToken(s)
active = -1
Repeat
token = GetNextSvgPointsToken()
Case token of
1: // Comma
Case active of
-1: // Error (fail silently)
1: active=2
2: // Error (fail silently)
EndCase
2: // Float
Case active of
-1: active = 1; point1 = ToReal(parseSvgPoints_lexeme)
1: // Error (fail silently)
2: active=-1; point2 = ToReal(parseSvgPoints_lexeme);
MessageBox("Points: "+point1+", "+point2)
// Do things with your points here!
EndCase
-1:
EndCase
Until token = -1
End
Function InitSvgPointsToken(s: String) : Boolean
Begin
parseSvgPoints_index0 = 0
parseSvgPoints_index1 = 0
parseSvgPoints_string = s
parseSvgPoints_strlen = Length(s)
parseSvgPoints_lexeme = ""
End
Function GetNextSvgPointsToken() : Integer
(*
Result:
-1: End of Stream / error
1: Comma
2: Float value
*)
Var
l: Integer
c: String
Begin
parseSvgPoints_index0 = parseSvgPoints_index1
result = -1
// Skip through whitespace
While (TRUE)
c = Mid(parseSvgPoints_string, parseSvgPoints_index0+1, 1)
If Svg_CharIsWhiteSpace(c) = FALSE then break
Inc(parseSvgPoints_index0)
If parseSvgPoints_index0 >= parseSvgPoints_strlen then break
Wend
parseSvgPoints_index1 = parseSvgPoints_index0
// Scan through until a delimiter is met, incrementing index1
While (TRUE)
c = Mid(parseSvgPoints_string, parseSvgPoints_index1+1, 1)
If Svg_CharIsPointsDelim(c) then break
Inc(parseSvgPoints_index1)
If parseSvgPoints_index1 >= parseSvgPoints_strlen then break
Wend
If (parseSvgPoints_index1 - parseSvgPoints_index0) = 0 then Inc(parseSvgPoints_index1)
// Lexeme Isolatted, lies between index0 and index1
parseSvgPoints_lexeme = Mid(parseSvgPoints_string, parseSvgPoints_index0+1, (parseSvgPoints_index1-parseSvgPoints_index0))
result = -1
Conditions
(parseSvgPoints_lexeme = ','): result = 1
(Svg_StringIsFloat(parseSvgPoints_lexeme)): result = 2
EndConditions
End
Function Svg_CharIsPointsDelim(c: String) : Boolean
Begin
result = FALSE
If (c = ',') then result = TRUE ; exit
result = Svg_CharIsWhitespace(c)
End
Function Svg_CharIsNumeric(c: String) : Boolean
Var
a: Integer
Begin
a = Asc(c)
If (a >= 48) and (a <= 57) then result = TRUE else result = FALSE
End
Function Svg_CharIsWhitespace(c: String) : Boolean
Var
a: Integer
Begin
a = Asc(c) // Tab = 9, Space = 32, Newline = 10
If (a = 9) or (a = 32) or (a = 10) then result = TRUE else result = FALSE
End
Function Svg_StringIsFloat(s: String) : Boolean ; export
Var
l, i: Integer
radix: Integer = 0
c: String
Begin
result = FALSE
l = Length(s)
If l < 1 then exit
For i = 1 to l
c = Mid(s, i, 1)
If Not (Svg_CharIsNumeric(c) or (c = '-') or (c = '.')) then exit
If (i <> 1) and (c = '-') then exit
If (c = '.') then
Inc(radix)
If i = l then exit
Endif
If radix > 1 then exit
Next
result = TRUE
End
Begin
ParseSvgPoints("123,456 27.5,-50 500.0,-500.0")
End
Stay Subscribed
RSS feed or get updates by e-mail.
, subscribe to theYou can also contact me directly - I make an effort to reply to every e-mail.