regular expression that doesn't match a string if it's the text within an html anchor tag
I'm writing an auto linking extension for blogengine.net which auto links key phrases in the blog post to specific urls. The issue I'm finding is very often the list of phrases to auto link are sub sets of eachother, eg "bmw" is a subset of "bmw car leasing", so if I use a regex to autolink "bmw car leasing " first then auto link the phrase "bmw" next, the former is already auto linked. The precendence is important, the longer phrases must be auto linked first, then the smaller phrases which may be subsets of the longer ones.
What I need is a regex that will dismiss the match if it's already within an anchor tag, i.e my phrase should be dismissed.
I don't have to use regexes too often , so I'm not totally au fait with them, so far I've managed to put together a regex that will match on anchor tags, but not the 开发者_JS百科reverse which is what I need. eg <a\b[^>]*>stuff(.*?)</a>
Any suggestions and advice would be very welcome.
Addition and hopefully the final solution .... only time will tell:- After a bit of trial and error, the final regex I used is below. This is based on the solution I marked as the answer:-
(?<!<a [^<]+)(?<!<img [^<]+)(?<=[ ,.;!]+)search phrase goes here(?=[ ,.;&!]+)(?!!.*<\\a>)
It allows the text being matched on to be preceded and succeeded by a space and basic punctuation as well as allowing for encoded characters like non breaking spaces
etc. It also avoids anything in an img tag being matched.
I realise it's still not 100% but as far as the requirements go it will suffice.
Thanks to all for your help and input.
The trick is to use a lookbehind that's non greedy and then add a lookahead for the ending of the anchor element. I find using tools like Expresso makes it much easier to create this kind of regular expressions.
var text = "Final report of the commercial starship Nostromo, third officer reporting. The other members of the crew, Kane, Lambert, Parker, Brett, Ash and Captain Dallas, are dead. Cargo and ship destroyed. I should reach the frontier in about six weeks. With a little luck, the network will pick me up. This is Ripley, last survivor of the Nostromo, signing off.";
var phrases = new List<KeyValuePair<string, string>> {
new KeyValuePair<string,string>("Nostromo", "http://www.imdb.com/media/rm3374159872/tt0078748"),
new KeyValuePair<string,string>("starship Nostromo", "http://en.wikipedia.org/wiki/Alien_%28film%29#Spaceships_and_planets")};
foreach (var phrase in phrases.OrderByDescending(kv => kv.Key.Length))
{
text = new Regex("(?<!<a [^<]+)" + phrase.Key + "(?!!.*<\\a>)").
Replace(text, "<a href=\"" +
phrase.Value + "\">" +
phrase.Key + "</a>");
}
Result:
Final report of the commercial starship Nostromo, third officer reporting. The other members of the crew, Kane, Lambert, Parker, Brett, Ash and Captain Dallas, are dead. Cargo and ship destroyed. I should reach the frontier in about six weeks. With a little luck, the network will pick me up. This is Ripley, last survivor of the Nostromo, signing off.
Negative lookbehind and lookahead helps in such situations, the following matches something
only if it's not preceded with (lookbehind):
(?<!<a>)something
However, as pointed out many times before here on SO, regular expressions are not the best tool to parse HTML, they are used for lexical analysis, not parsing. For more information check out the question linked to in the first comment to your question.
精彩评论