Ah, yes. Perhaps a more general form for the html entities, e.g.,:
/&(?!.+?;)/
Update: I have no idea what I was 'thinking' here. Excellent and appreciated corrections to this below... | [reply] [d/l] |
That won't just exclude HTML entities from being matched, it will exclude any & character that is in the same line as a semicolon somewhere to the right of it, because .+? also matches whitespace.
Instead, you should match for HTML/XML entities specifically. There are three forms that they can take, and the corresponding regexes for matching them would be:
/&#[0-9]+;/ - character referenced by decimal number
/&#x[0-9a-f]+;/i - character referenced by hexadecimal number
/&[a-z]+;/i - character referenced by name
Putting it together, you get this regex for matching an HTML entity:
/&(?:#(?:[0-9]+|x[0-9a-f]+)|[a-z]+);/i
Although that's kinda messy and pedantic, and you can probably get away with using this simplified version:
/&#?[0-9a-z]+;/i
(Unlike the more pedantic version, it would match some false positives such as &#amp; or &1a2b3c;, but what are the chances such constructs will appear in the input document?)
To do what the OP requested, wrap everything after the & in a negative look-ahead bracket like choroba suggested:
# 10 20 30 40 50
# ---------'---------'---------'---------'---------'----
my $str = "& ... & ... & ... &no_entity; ... & ... ;";
while ($str =~ /&(?!#?[0-9a-z]+;)/gi) {
print "Found ampersand at position ".pos($str)."\n";
}
Output:
Found ampersand at position 32
Found ampersand at position 48
(i.e. it only matches the last two & characters in $str) | [reply] [d/l] [select] |
| [reply] |
It fails on a string like this: "I saw a dog & a cat;".
A safer solution, would be: /&(?!#?[a-zA-Z0-9]+;)/
| [reply] [d/l] [select] |
| [reply] [d/l] |