0

I want to parse a string from inside another string, based on a start and end string pattern.

The example is parsing an ip address, however this could be any string, and not necessarily an IP.

Is there a better / more efficient way of doing this:

function parse(str,start,end){
    var ls = str.indexOf(start);
    if(str && ls !== -1) return str.substring(ls+start.length,str.indexOf(end,ls));
    return false;
}

var res = "wlan0: adding default route via 192.168.0.1";
console.log(parse(res,"route via ","\n"));

192.168.0.1

Vicky Gonsalves
  • 11,593
  • 2
  • 37
  • 58
crankshaft
  • 2,607
  • 4
  • 45
  • 77

2 Answers2

1

You could consider using regular expressions. This could be a generic beginning (take a look here for a proper RegExp.escape method):

function parse(str, start, end) {
    var start_expr = RegExp.escape(start);
    var end_expr = RegExp.escape(end);
    var regex = new RegExp( start_expr + "(.*)(?=" + end_expr + ")" );
    var match = str.match(regex);
    return match[1];
}

You may have to adjust it for your needs, as regex might not directly accept some escape sequences you are used to (e.g. "\n" in your example).

Community
  • 1
  • 1
matpop
  • 1,969
  • 1
  • 19
  • 36
  • 1
    You should not build regular expressions from raw strings. This is very error-prone. Strings [must be escaped](http://stackoverflow.com/q/3561493/18771) before you can use them in a regex. – Tomalak Nov 17 '13 at 14:37
  • I assumed `start` and `end` to be already escaped, if necessary (e.g. don't want the "$" to be escaped in the example). Thanks for pointing it out. I wouldn't use that regex to match a string at end of line, it was just to stay generic yet simple. – matpop Nov 17 '13 at 15:06
  • Well, according to the intended use the OP is showing, input strings are not escaped. Apart from that it's bad design if a function expects "specially treated" parameters. Because if you forget, your function breaks at run-time (compare: *the principle of least surprise*) -- And apart from *that*: If there already *were* defined regular expressions, nobody would need a separate function just to use them on a string, right? ;) – Tomalak Nov 17 '13 at 15:23
  • Of course you're right, in fact I wouldn't wrap that into a function in real life, again, I only wanted to be clear for the specific question, ended up with a mess instead. I think I'd better delete it – matpop Nov 17 '13 at 15:38
  • No, if you include proper regex escaping the answer is fine. You don't need to repeat the `Regexp.escape()` function, mentioning where it came from would be enough. – Tomalak Nov 17 '13 at 15:41
1

You could clean it up a little:

function parseSubstring(str, after, until) {
    var pos0 = after ? str.indexOf(after) : 0,
        posS = pos0 > -1 ? pos0 + after.length : str.length,
        posE = until ? str.indexOf(until, posS) : str.length;

    if (posE >= posS) {
        return str.substring(posS, posE);
    }
}

var input = "wlan0: adding default route via 192.168.0.1",
    part = parseSubstring(input, "route via ");
    // -> "192.168.0.1"

On a general note, don't return false if you don't actually want to return a Boolean value. This is not PHP, returning false to indicate an error is the Wrong Thing. If there is no defined result of a function, don't return one at all.


You could also augment the String prototype.

String.prototype.snip = function(after, until) {
    var pos0 = after ? str.indexOf(after) : 0,
        posS = pos0 > -1 ? pos0 + after.length : this.length,
        posE = until ? this.indexOf(until, posS) : this.length;

    if (posE >= posS) {
        return this.substring(posS, posE);
    }
}

var input = "wlan0: adding default route via 192.168.0.1",
    part = input.snip("route via ");
    // -> "192.168.0.1"

Note how not passing in the until argument translates to "up to the end of the string". Passing the empty string in the after argument would translate to "from the start".

Tomalak
  • 332,285
  • 67
  • 532
  • 628