Search code examples
javascriptregexstringxojo

What is this String.Replace method doing?


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?


Solution

  • 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.