views:

512

answers:

6

In javascript, I've got a block of HTML like this:

<h2>{title}</h2>
<p><a href="{url}">{content}</a></p>

And I'm trying use regex "match" to spit out an array of all the {item}'s. So my output should look like:

['title', 'url', 'content']

I've gotten as far as:

var pattern = new RegExp("\{[a-zA-Z]+\}+");
var match = pattern.exec("{Sample} bob {text}");

But it's only returning the first tag.

This is just beyond my regex skills. Can anyone help?

Cheers!

+2  A: 

I think you want:

var pattern = new RegExp("\{[a-zA-Z]+\}+", "g");

The second option is a flag telling it to search the entire string and return all matches.

See: http://www.evolt.org/article/Regular_Expressions_in_JavaScript/17/36435/ for more details.

grieve
A: 

@grieve - good tip, tho it's still only returning the first one. I'll keep playing.

@litb - getElementsByTagName will only return tags. I need the custom elements contained in curly brackets. getElementsByTagName won't return those. right?

Corey Maass
+7  A: 

You need to create a pattern with the global flag:

var pattern = new RegExp("\{[a-zA-Z]+\}", "g");

or:

var pattern = /\{[a-zA-Z]+\}/g;

Then you can call the match() method on your string to get a list of matches:

var matches = "{Sample} bob {text}".match(pattern);
Jan Goyvaerts
I think "\{[^}]+\}" is a safer bet than "\{[a-zA-Z]\}", but if there are no other letters/symbols in Corey's model I guess it's okay. +1
Tomalak
Not at all. Corey himself used [a-zA-Z] so I kept that. A regex should always be as strict as possible, never as loose as possible. If one day Corey has an HTML file with a missing }, [^}]+ will run haywire, while [a-zA-Z] won't.
Jan Goyvaerts
A: 

Ah hah! Thanks, Jan (and Grieve). I think I got off path with using exec for testing.

Corey Maass
+1  A: 

Much as I like to roll my own RegExp (and you really just need the global flag), have you looked at prototype templates, Trimpath JST or anything like that?

Because possibly rolling your own won't be as efficient for reuse as the above examples. EG:

String.prototype.template = function (obj) {
 return this.replace(/{([^{}]+)}/g,
  function (full, word) {
   return((typeof obj[word]==='string'||typeof obj[word]==='number')?obj[word]:full);
  }
 );
};

"The {adj1} {adj2} {noun}.".template({adj1: 'lazy',adj2: 'brown', noun: 'dog'})
==> "The lazy brown dog."

This runs your regex each time, while I believe the prototype templates basically does it once.

dlamblin
+1  A: 

Have you tried this yet?

<script>
var text = '<h2>{title}</h2>\n<p><a href="{url}">{content}</a></p>';
var regex = /\{[a-z]+\}/ig;
var result = text.match(regex);
for (var i = 0; i < result.length; i++) {
    console.debug(i + ". " + result[i]);
}
/*
gives:
0. {title}
1. {test}
2. {url}
3. {content}
*/
</script>
Kristof Neirynck