1

I'm trying to port this Javascript code to another language (Xojo):

Vertices.fromPath = function(path, body) {
    var pathPattern = /L?\s*([\-\d\.e]+)[\s,]*([\-\d\.e]+)*/ig,
        points = [];

    path.replace(pathPattern, function(match, x, y) {
        points.push({ x: parseFloat(x), y: parseFloat(y) });
    });

    return Vertices.create(points, body);
};

I know that path should be a string containing x y pairs of numbers (in SVG format like "L 50 25 L 100 10"). Am I correct in thinking that this would split the earlier string into two objects 50,25 and 100,10 and then push them onto the points array?

Garry Pettet
  • 8,096
  • 22
  • 65
  • 103

2 Answers2

2

Not sure if you know that /L?\s*([\-\d\.e]+)[\s,]*([\-\d\.e]+)*/ig is a regex search string.

If I decypher that quickly, I'd say that it seeks an optional "L" at the start, then optional whitespace, then a number (i.e. anything containing a digit, period, minus or "e"), whitespace or comma, another number, and the parentheses around the numbers mean that these are the matched values passed to the function in the replace() call. The "ig" at the end are options, where "i" means to ignore case IIRC.

So, that code only seems to fetch two numbers, optionally preceded by an "L". It then reads those numbers into x and y, and appends them to the points array.

In Xojo you'd have to do that in a loop (Xojo has no support for local functions), using the RegEx class to parse the string repeatedly. To convert the scanned numbers into doubles, use the Val() function.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
1

While it is true that the regular expression in your question will match two numbers that follow a single 'L' letter, it will also match many other things that cannot be parsed as valid numbers. You are correct, this code will create two objects that have their X and Y properties populated from the matched numbers.

Using Realbasic.Points to hold the coordinates, this functionality could be achieved by the following Xojo snippet:

Dim inString As String = "L 50 25 L 100 10"
Dim outArray(-1) As Realbasic.Point

Dim rx As New RegEx()
Dim match As RegExMatch
rx.SearchPattern = "L?\s*([\-\d.e]+)[\s,]*([\-\d.e]+)*"
match = rx.Search(inString) // Get the first matching part of the string, or nil if there's no match
While match <> nil
    dim x As Integer = match.SubExpressionString(1).Val() // X coordinate is captured by the first group
    dim y As Integer = match.SubExpressionString(2).Val() // Y coordinate is captured by the second group
    dim p As new REALbasic.Point(x, y)
    outArray.Append(p)
    match = rx.Search() // Get the next matching part, or nil if there's no more
Wend

If you need to match only numbers and want to prevent errors during the String->Double conversion, you should update the regex pattern to something like this:

"L?\s+(\-?\d+(?:\.\d+)?(?:e-?\d+)?)[\s,]+(\-?\d+(?:\.\d+)?(?:e-?\d+)?)"

The original pattern would match 'Lee ...---...', this updated one would require at least one space between the 'L' and the numbers, and would not match on characters that could be parts of a number, but they do not form a valid numeric representation.

awagner
  • 58
  • 4