Glossario e regular expression

martedì 10 giugno 2014 - 18.09

borgorosso Profilo | Newbie

Salve a tutti,
cerco di spiegare brevemente lo scenario.

Ho un sito web con degli articoli.
Vorrei che alcune parole di questi articoli fossero collegate ad altre pagine. Ad esempio, che ogni volta che compare la parola SPORT questa stessa parola fosse collegata alla pagina www.gazzetta.it.

Ovviamente le parole sono da linkare sono in una tabella di MySql.

Ho trovato una espressione regolare molto interessante, ma non riesco ad utilizzarla nel modo corretto.

Dim myRegex As New Regex("(?i)\bparola\b(?=[^<>]*(?:<\w|$))", RegexOptions.IgnoreCase Or RegexOptions.Compiled)

0v3rCl0ck Profilo | Guru

>Ho trovato una espressione regolare molto interessante, ma non
>riesco ad utilizzarla nel modo corretto.
>
>Dim myRegex As New Regex("(?i)\bparola\b(?=[^<>]*(?:<\w|$))",
>RegexOptions.IgnoreCase Or RegexOptions.Compiled)
>

L'idea mi sembra buona, quella regular funziona bene, con qualche nota:

(?i) = asserisce che la regular deve essere case insensitive, quindi puoi omettere RegexOptions.IgnoreCase, in realtà io preferisco non utilizzare (?i) e specificare RegexOptions.IgnoreCase

RegexOptions.Compiled = è un ottimizzazione che permette a .net di compilare alla prima esecuzione un algoritmo di ricerca, senza doverla ricompilare ad ogni esecuzione, questo sempre essere sempre un vantaggio, ma non è così, dovresti fare dei load test, prima di aggiungere questa opzione per partito preso.

(?=[^<>]*(?:<\w|$)) = questa parte a cosa ti serve? in pratica se dopo la parola da cercare c'è un '<' o '>' il match salta, esempio 'adsdadd parola < asdasd' questo salta, invece lo prende se ad esempio è così 'asdasasda parola <adasda ldkalda', se dopo '<' ci sono caratteri o numeri

Tutta la regular è spiegata così (eng):

Assert position at a word boundary (position preceded or followed—but not both—by a Unicode letter, digit, or underscore) «\b»
Match the character string “parola” literally (case insensitive) «parola»
Assert position at a word boundary (position preceded or followed—but not both—by a Unicode letter, digit, or underscore) «\b»
Assert that the regex below can be matched, starting at this position (positive lookahead) «(?=[^<>]*(?:<\w|$))»
Match any single character NOT present in the list “<>” «[^<>]*»
Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match the regular expression below «(?:<\w|$)»
Match this alternative (attempting the next alternative only if this one fails) «<\w»
Match the character “<” literally «<»
Match a single character that is a “word character” (Unicode; any letter or ideograph, digit, connector punctuation) «\w»
Or match this alternative (the entire group fails if this one fails to match) «$»
Assert position at the end of a line (at the end of the string or before a line break character) (line feed) «$»

a prescindere dalla regular, che semplificata potrebbe essere

new Regex("\bparola\b", RegexOptions.IgnoreCase)

devi applicarla agli articoli prima di stamparli sul browser, quindi come flusso pensavo ad una cosa del genere:

1 - query a db per ottenere l'articolo

2 - query a db per ottenere la lista delle parole conosciute e relativi link della fonte

3 - fai una bella regex.replace per ogni parola conosciuta, costruendo la regular con uno string.format, qualcosa del genere:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

in pratica $+ verrà sostituito con la parola trovata.

poi il tutto può essere un po' ottimizzato, mettendo la query a db della lista delle parole conosciute in una cache per evitare di richiamare sempre il db.



Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

borgorosso Profilo | Newbie

Il tuo suggerimento è quello di iterare sui vari termini in db?

Una cosa del tipo


Function glossario()
For i as integer = 0 to table_termini.rows.count -1
parolaConosciutaPresaDaDb = table.rows(i)("parolaConosciutaPresaDaDb")
Dim myRegex As New Regex(String.Format("\b{0}\b", parolaConosciutaPresaDaDb), RegexOptions.IgnoreCase)
return myRegex.Replace(articolo, String.Format("<a href='{0}'>$+</a>", linkDellaParolaConosciutaPresaDaDb))
Next
End Function

?

aggiungo: quella parte della Reg mi serve per escludere quelle parole che sono già all'interno di un TAG




0v3rCl0ck Profilo | Guru

>Il tuo suggerimento è quello di iterare sui vari termini in db?
>

si esatto.

>Una cosa del tipo
>
>
>Function glossario()
> For i as integer = 0 to table_termini.rows.count -1
>parolaConosciutaPresaDaDb = table.rows(i)("parolaConosciutaPresaDaDb")
>Dim myRegex As New Regex(String.Format("\b{0}\b", parolaConosciutaPresaDaDb),
>RegexOptions.IgnoreCase)
>return myRegex.Replace(articolo, String.Format("<a href='{0}'>$+</a>",
>linkDellaParolaConosciutaPresaDaDb))
> Next
>End Function

direi che può funzionare, se poi quel table lo tieni in cache, puoi evitare di querare il db tutte le volte.

poi è normale che ci siano algoritmi ancora più ottimizzati, però prima di volere ottimizzare a tutti i costi, controlla se per te è sufficiente così, non ne vale mai la pena di complicare il codice se non serve. Se sei preoccupato per le chiamate che puoi avere, e hai un idea di quante persone apriranno quella pagina, fai dei load test per scoprire se potresti avere dei bottleneck (http://msdn.microsoft.com/en-us/library/ms182594.aspx).

>
>aggiungo: quella parte della Reg mi serve per escludere quelle
>parole che sono già all'interno di un TAG

ok allora bravo, ottima regular!

Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

borgorosso Profilo | Newbie

sono davvero spiacente di non averne il merito, la regular l'ho trovata online

se hai qualche suggerimento sulla ottimizzazione ne sarei contento

grazie di tutto

0v3rCl0ck Profilo | Guru

ti posso consigliare di mettere in cache la risposta alla chiamata per avere tutti i termini da sotituire, sfruttando la MemoryCache di System.Runtime.Caching:

http://msdn.microsoft.com/library/system.runtime.caching.memorycache.aspx

http://www.allinsight.de/caching-objects-in-net-with-memorycache/


Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2025
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5