2

As a follow up to this question (not by me), I need to replace leading numbers of an id with \\3n (where n is the number we're replacing).

Some examples:

"1foo"    -> "\\31foo"
"1foo1"   -> "\\31foo1"
"12foo"   -> "\\31\\32foo"
"12fo3o4" -> "\\31\\32fo3o4"
"foo123"  -> "foo123"

Below is a solution that replaces every instance of the number, but I don't know enough regex to make it stop once it hits a non-number.

function magic (str) {
    return str.replace(/([0-9])/g, "\\3$1");
}

... Or is regex a bad way to go? I guess it would be easy enough to do it, just looping over each character of the string manually.

Community
  • 1
  • 1
  • can you post your expected out – Raghavendra Aug 26 '15 at 10:38
  • 1
    @Raghavendra I think I did. After the arrow in the examples is the expected output. –  Aug 26 '15 at 10:39
  • I think you need to use a reverse string approach here and use a look-ahead. – Wiktor Stribiżew Aug 26 '15 at 10:41
  • you can do like this '123fo3o4'.split(/(\d+)/) in my opinion – Raghavendra Aug 26 '15 at 10:53
  • @Raghavendra and then run through the first one with numbers, replace each with the backslash string and put it all together? It could work, yes. But then I think I'd rather just use a regular `for ... of` loop to traverse the string and break out once we hit a non-digit. –  Aug 26 '15 at 10:55

3 Answers3

4

Here is a way to achieve what you need using a reverse string + look-ahead approach:

function revStr(str) {
    return str.split('').reverse().join('');
}

var s = "12fo3o4";
document.write(revStr(revStr(s).replace(/\d(?=\d*$)/g, function (m) {
    return m + "3\\\\";
 }))
);

The regex is matching a number that can be followed by 0 or more numbers only until the end (which is actually start) of a reversed string (with \d(?=\d*$)). The callback allows to manipulate the match (we just add reversed \\ and 3. Then, we just reverse the result.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
4

Just use two steps: first find the prefix, then operate on its characters:

s.replace(/^\d+/, function (m) {
    return [].map.call(m, function (c) {
        return '\\3' + c;
    }).join('');
});

No need to emulate any features.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
  • yes nice one. got new one today, missed to see the replace api – Raghavendra Aug 26 '15 at 10:59
  • 1
    This won't work in old browsers (like IE8), otherwise, a nice one. Still, it also performs split and join. I also think you need to use `\\\\3` to get actually `\\3` in the replacement string. – Wiktor Stribiżew Aug 26 '15 at 11:25
  • The \\ vs \\\\ part is moot for me personally, but actually the browser support isn't. Thanks for pointing that out. –  Aug 26 '15 at 11:28
2

Here is how I would have done it:

function replace(str) {
    var re = /^([\d]*)/;
    var match = str.match(re)[0];        
    var replaced = match.replace(/([\d])/g, "\\3$1");        
    str = str.replace(match, replaced);
    return str;
}

document.write(replace("12fo3o4"));

Don't get me wrong: the other answers are fine! My focus was more on readability.

KeyNone
  • 8,745
  • 4
  • 34
  • 51