2009-10-13 8 views
0

I am working on improving our glossary functionality in a custom CMS that is running with classic ASP (ASP 3.0) on IIS with VBScript code. I am stumped on a regex challenge I cannot solve.Défi Regex: Exprime la phrase uniquement si l'extérieur d'un <a href> tag

Here is the current code:

 If InStr(ART_ArticleBody, "href") = False then 
    sql="SELECT URL, Term, RegX FROM GLOSSARYDB;" 
    Set rsGlossary = Server.CreateObject("ADODB.Recordset") 
    rsGlossary.open sql, strSQLConn 
    Set RegExObject = New RegExp 
     While Not rsGlossary.EOF 
     URL = rsGlossary("URL") 
     Phrase = rsGlossary("RegX") 
     With RegExObject 
    .Pattern = Phrase 
    .IgnoreCase = true 
    .Global = false 
     End With 
     set expressionmatch = RegExObject.Execute(ART_ArticleBody) 
     if expressionmatch.count > 0 then 
     For Each expressionmatched in expressionmatch 
     RegExObject.Pattern = Phrase 
     URL = "<a href=" & URL & ">"& expressionmatched.Value & "</a>" 
    ART_ArticleBody = RegExObject.Replace(ART_ArticleBody, URL) 
     next 
     end if 
     rsGlossary.movenext 
     wend 
     rsGlossary.movefirst 
    Set RegExObject = nothing 
    end if 

Instead of skipping putting glossary links in any article that has an href in it, as the above code does, I would like to change the code to process every article but have the RegEx pattern avoid matching on a glossary entry if the match is inside of an a tag.

For example, in italics below is a test example for this regex entry in my DB: ROI|return on investment|investment return

Here is a link that uses the glossary term: <a href="ROI.htm">Info on return on investment</a>. Now, here is the glossary term in plain text, not inside of a link: return on investment. We want to find the third instance of a match but not find the first two because they are both inside of a HTML link.

In the above text, if I were processing the article for the glossary entry "ROI|return on investment|investment return" I do not want to match on the first or second occurance that match because they are in an a tag. I need the regex pattern to skip over those matches and just match on any that are not inside of an a tag.

Any help on this would be greatly appreciated.

+1

+0

Ainsi, étant donné un ensemble de phrases possibles, vous voulez trouver toutes les instances de l'un d'eux qui ne tombe pas à l'intérieur ''? –

+0

Oui. C'est correct. – kgaebler

Répondre

1

Essayez cette regex:

<a\b[^<>]*>[\s\S]*?</a>|(ROI|return on investment|investment return) 

Cela correspond à un point d'ancrage HTML, ou l'un des termes que vous recherchez. Les termes sont capturés dans le groupe numéro 1. Donc, dans votre code VBScript, vérifiez si le premier groupe de capture correspond à quelque chose, et vous avez un de vos mots-clés à l'extérieur d'un tag> <.

Cette regex ne fonctionnera en effet pas correctement si vous avez imbriqué des balises a> <. Cela ne devrait pas poser de problème, car les ancres ne sont normalement pas imbriquées les unes dans les autres. Si c'est un problème, vous ne pouvez pas le résoudre avec des expressions régulières VBScript/JavaScript. La regex ne fonctionnera pas non plus correctement si vous avez des tags> < qui manquent leurs tags de fermeture. Si vous voulez prendre cela en compte, essayez cette regex:

<a\b[^<>]*>(?:(?:(?!<a\b)[\s\S])*?</a>)?|(ROI|return on investment|investment return) 
+0

OMG. Jan Goyvaerts pour de vrai? C'est génial. Mec, roches RegexBuddy. Merci beaucoup pour l'aide. Je vais essayer. – kgaebler

+0

J'aime vraiment la technique. Donc, vous mettez les choses que vous voulez trouver en parens d'un côté de la | et vous mettez les choses que vous voulez ignorer de l'autre côté sans les parenthèses et vérifiez juste si vous avez une allumette dans le groupe de capture pour un match donné. Excellent. Juste connecté un couple de synapses ici. Merci. – kgaebler

+0

Voilà comment cela fonctionne. –

0

You can't solve it because it can't be done, at least not with 100% reliability. HTML is not a "regular" language in the regular expression sense. Like the saying goes, when you have a hammer, everything starts to look like a nail. There are some things regular expressions aren't good at. This is one of them.

Most languages have some form of HTML parsing library as standard or easily obtained. Use those. That's what they were designed for.

0

In general, you can't use a regular expression to recognize arbitrarily nested constructs (such as bracket-delimited HTML tags). If you had solved this problem, there's be a lot of mathematicians lining up to hear about it. :)

Having said that, .NET does indeed offer an extension to regular expressions that permits what I just said was impossible, and--even better!--the sample chapter for the great "Mastering Regular Expressions" available here arrive à couvrir cette caractéristique.

+0

Cette question est à propos de ASP classic –

1

Ce problème est, comme on dit, "non trivial" dans son état actuel. Toutefois, si vous pouvez modifier votre système pour une balise de sortie plus sémantique, il rendrait les choses beaucoup plus facile:

<a href="ROI.htm">undesired tag match</a> 
This is <span class="tag">a tag</span> 

Dans ce cas, vous pouvez simplement rechercher:

(?<=<span class=\"tag\">)(phrase1|phrase2|phrase3)(?=</span>) 

Ou quelque chose d'un peu plus robuste

(?<=<span class=\"tag\">).+?(?=</span>) 

de cette façon, vous pouvez facilement concentrer vos recherches aux données dans un <span> spécifique, et laisser tout le reste de côté.

+0

C'est ma base de données donc j'ai un contrôle total sur le balisage. Je peux m'assurer que chaque est écrit comme vous l'avez écrit ci-dessus. Avec cela en place, est-il possible de le faire avec des lookaheads négatifs ou lookbehinds? – kgaebler

+0

Rex, si je comprends bien ce que vous dites, vous dites que si je préférais juste baliser tous mes mots de glossaire avec des balises, il serait facile de les trouver. Bien que j'apprécie les commentaires, ce n'est pas ce que j'essaie de faire. J'essaie de modifier le texte de l'article juste avant de le servir de sorte que les entrées du glossaire, telles que définies dans une base de données de glossaire, apparaissent sous forme de liens. Si j'étais prêt à pré-traiter les articles et à ajouter des balises de span comme vous le suggérez, alors je ferais aussi bien de coder en dur les liens vers les entrées du glossaire. – kgaebler

+0

@kgaebler en effet, vous pourriez aussi bien!Vous stockez une copie basse fidélité de vos données en tant que maître et essayez de reconstruire une version haute fidélité au moment de l'extraction. C'est un jeu perdant, comme vous le verrez dans les autres réponses ici. –

0
(accounts receivable|A/R)(?!((?!</?a\b).)*</a) 

(phrase1|phrase2|phrase3)(?!((?!</?a\b).)*</a) 

L'approche ci-dessus semble fonctionner, au moins dans mon logiciel RegexBuddy. Je n'ai pas compris tout seul. Avait de l'aide d'un gourou. Il est temps de le tester dans mon code ASP. Merci à tous ceux qui ont contribué. Je suis sûr que je n'ai pas décrit suffisamment ce dont j'avais besoin pour que vous trouviez la solution ci-dessus. Mea culpa.