6

Not a complete newbie, but I still don't understand everything about Regular expressions. I was trying to use Regex to strip out <p> tags and my first attempt

<p\s*.*>

was so greedy it caught the whole line

<p someAttributes='example'>SomeText</p>

I got it to work with

((.|\s)*?)

This seems like it should be just as greedy, can anyone help me understand why it isnt?

Trying to make this question as language non-specific as possible, but I was doing this with ColdFusion's reReplaceNoCase if it makes a lot of difference.

invertedSpear
  • 10,864
  • 5
  • 39
  • 77

3 Answers3

12

The key difference is the *? part, which creates a reluctant quantifier, and so it tries to match as little as possible. The standard quantifier * is a greedy quantifier and tries to match as much as possible.

See e.g. Greedy vs. Reluctant vs. Possessive Quantifiers

As Seth Robertson noted, you might want to use a regex that does not depend on the greedy/reluctant behaviour. Indeed, you can write a possessive regex for best performance:

<p\s*+[^>]*+>

Here, \s*+ matches any number of white space, while [^>]*+ matches any number of characters except >. Both quantifiers do not track back in case of a mismatch, which improves runtime in case of a mismatch, and for some regex implementations also in case of a match (because internal backtracking data can be omitted).

Note that, if there are other tags starting with <p (didn't write HTML directly for a long time), you match these too. If you don't want that, use a regex like this:

<p(\s++[^>]*+)?>

This makes the whole section between <p and > optional.

Community
  • 1
  • 1
Christian Semrau
  • 8,913
  • 2
  • 32
  • 39
  • Thanks, helping me to understand a lot here. Little confused on what the '++' is doing I get that this will only match if p followed > or p [space]+anything but > followed by >, but it seems like the second + is redundant. What am I not getting there? – invertedSpear Jun 06 '11 at 21:20
  • 1
    The second `+` is the quantifier modifier: It makes the quantifier `+` possessive: `\s+` is greedy (match most), `\s+?` is reluctant (match least), `\s++` is possessive (match most without backtracking). – Christian Semrau Jun 06 '11 at 21:32
  • I have some reading to do on backtracking I think. I have a very tenuous grasp on when it will and won't occur. Thanks for the explanation. – invertedSpear Jun 06 '11 at 21:43
  • Consider this article (and the rest of the site): http://www.regular-expressions.info/catastrophic.html – Christian Semrau Jun 06 '11 at 21:47
2

Well, either regex will match absolutely anything, so the question is moot. Using non-greedy parser will probably come closer to what you want but still could have very unexpected results.

While you should not be matching html/xml with a RE, you probably want something like:

<p\s*([^>]*)>

Which would put any attributes of p into $1.

Seth Robertson
  • 30,608
  • 7
  • 64
  • 57
0
<p\s*.*>

Is looking for 'p', 0 or more spaces, 0 or more characters, '>' . The group "any character" contains '>', so the regular expression find the whole line.

Alessandro Pezzato
  • 8,603
  • 5
  • 45
  • 63