Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript equivalent of Ruby's String#scan

Does this exist?

I need to parse a string like:

the dog from the tree

and get something like

[[null, "the dog"], ["from", "the tree"]]

which I can do in Ruby with one RegExp and String#scan.

JavaScript's String#match cannot handle this as it just return what the RegExp is matched and not the capturing groups, so it returns something like

["the dog", "from the tree"]

Because I used String#scan many times in my Ruby application, it would be nice if there was a quick way to replicate this behavior in my JavaScript port.

EDIT: Here is the RegExp I'm using: http://pastebin.com/bncXtgYA

like image 899
itdoesntwork Avatar asked Dec 15 '12 19:12

itdoesntwork


2 Answers

String.prototype.scan = function (re) {
    if (!re.global) throw "ducks";
    var s = this;
    var m, r = [];
    while (m = re.exec(s)) {
        m.shift();
        r.push(m);
    }
    return r;
};
like image 166
melpomene Avatar answered Oct 10 '22 10:10

melpomene


ruby's scan() method will return nested array only when capture group is specified. http://ruby-doc.org/core-2.5.1/String.html#method-i-scan

a = "cruel world"
a.scan(/\w+/)        #=> ["cruel", "world"]
a.scan(/.../)        #=> ["cru", "el ", "wor"]
a.scan(/(...)/)      #=> [["cru"], ["el "], ["wor"]]
a.scan(/(..)(..)/)   #=> [["cr", "ue"], ["l ", "wo"]]

Below is modified version of melpomene's answer to return flat array if appropriate.

function scan(str, regexp) {
    if (!regexp.global) {
        throw new Error("RegExp without global (g) flag is not supported.");
    }
    var result = [];
    var m;
    while (m = regexp.exec(str)) {
        if (m.length >= 2) {
            result.push(m.slice(1));
        } else {
            result.push(m[0]);
        }
    }
    return result;
}
like image 26
ypresto Avatar answered Oct 10 '22 10:10

ypresto