tags:

views:

315

answers:

6

I have a pattern like this that matches multiple sets of values:

(((\w+) (\d+))+)

I think this would match:

one 1 two 2 three 3 four 4 five 5

But because I don't know how many repeats there are I don't know what to put in the output.

For instance I need to get the results into something like this:

<span class="one">1</span>
<span class="two">2</span>
<span class="three">3</span>
<span class="four">4</span>
<span class="five">5</span>

So something like this:

/(((\w+) (\d+))+)/ig, "<span class=\"$3\">$4</span>"

Would not work, because I need to create a variable number of span elements.

Is there something I'm missing here?

Thanks!

+1  A: 

I think you're just gonna want to split by whitespace in this case:

s = "one 1 two 2 three 3 four 4 five 5";

// Replace runs of whitespace with a single space, and trim...
s.replace(/\s+/g, ' ');
s.replace(/^\s+|\s+$/g, '')

// And split string into an array
var parts = "one 1 two 2 three 3 four 4 five 5".split(' ')

for (var i=0; i<parts.length; i++){

    // Get your pieces
    var name = parts.shift();
    var num = parseInt(parts.shift());

    // Create your span
    var span = $('<span></span>').attr('class', name).text(num);

}
Triptych
A: 

Doesn't your question give your answer? I was just testing with the javascript console:

>>> "one 1 two 2 three 3 four 4 five 5".replace(/(((\w+) (\d+))+)/ig, "<span class=\"$3\">$4</span>")
<span class="one">1</span> <span class="two">2</span> <span class="three">3</span> <span class="four">4</span> <span class="five">5</span>

>>> "one 1 two 2 three 3 four 4".replace(/(((\w+) (\d+))+)/ig, "<span class=\"$3\">$4</span>" )
<span class="one">1</span> <span class="two">2</span> <span class="three">3</span> <span class="four">4</span>

>>> "one 1 two 2 three 3".replace(/(((\w+) (\d+))+)/ig, "<span class=\"$3\">$4</span>" )
<span class="one">1</span> <span class="two">2</span> <span class="three">3</span>

>>> "one 1 two 2 three 3 foo five 5".replace(/(((\w+) (\d+))+)/ig, "<span class=\"$3\">$4</span>" )
<span class="one">1</span> <span class="two">2</span> <span class="three">3</span> foo <span class="five">5</span>

It seems to do exactly what you want.

Edit: original answer below; I missed the jquery tag, thought it was a regexp question...

Don't try to match them all at once; let the /g handle that...

bash$ echo "one 1 two 2 three 3 four 4 five 5" | \
      sed -e 's/\([[:alpha:]]\+\)\s*\([[:digit:]]\+\)\s*/<span class="\1">\2<\/span>\n/g'

which gives

<span class="one">1</span>
<span class="two">2</span>
<span class="three">3</span>
<span class="four">4</span>
<span class="five">5</span>
Stobor
D'Oh! missed the jquery tag...
Stobor
You could be right, am I stupid? 0.o Will test more and get back to you, thanks!
Jourkey
it works, but only b/c the regex doesn't account for the space between pairs.
rampion
A: 

The following works in VIM.

:%s/\(\w\+\) \(\d\+\)/<span class="\1">\2<\/span>\r/ig

Similar should work in jquery.

Canopus
Hi, can you explain what's going on here? Because I don't understand it at all and hence can't adapt.Thanks!
Jourkey
I tried this in VI editor which supports regex and it works. I dont know what jquery is but I expect it to work there. it is basically /(\w+) (\d+)/<span class="\1">\2</span>/ig with appropriate escaping for vi editor
Canopus
A: 

Why would you not have those in an array, which makes more sense (if you are in fact making a bunch of spans with numbers):

var arr = ['one','two','three','four','five','six','seven','eight','nine','ten'];

$.each(arr, function(i, val) {
   var $span = $('<span></span>').attr('class', val).text(i+1);
   $('#someDiv').append($span);
});
karim79
Sorry I'm not, it's just an example, need to learn how to sync the number of elements with the # of repeats in regex.
Jourkey
+2  A: 

Instead of trying to repeat your matches, just use (\w+) (\d+) and repeat the replace multiple times (which is what the g global replace flag does).

Note: the i flag you have is redundant, since \w includes both cases and \d is only numeric.

Assuming all other parts of the page setup appropriately and $j is jQuery object, this will work as desired:

var MyText = $j(something).text();

HtmlContent = MyText.replace( /(\w+) (\d+)/g , '<span class="$1">$2</span>' );

$j(something).html( HtmlContent );
Peter Boughton
Right: the regex only has to match one pair of tokens at a time; it's the regex _engine_ that iterates over the matches.
Alan Moore
+2  A: 

What you're missing is that your regex matches the entire string, when you want to replace it piece by piece:

  • /(\w+) (\d+)/ matches "five 5" or "one 1", but not "one 1two 2"
  • /(?:(\w+) (\d+))+/ matches "one 1" or "one 1two 2" or "one 1two 2three 3", etc

+ matches the preceeding pattern 1 or more times.

(Side note: (?:...) is like (...) except it doesn't capture anything into $1, $2, etc, it just groups things.)

So for your problem, you just need to drop the +:

/(\w+) (\d+)/ig, "<span class=\"$1\">$2</span>"

The /g (global) flag will take care of repeating your substitution for every time the pattern matches.

rampion