[ASP] Regular expressions werken soms wel/niet

Pagina: 1
Acties:

  • Not Pingu
  • Registratie: November 2001
  • Laatst online: 18-08 10:07

Not Pingu

Dumbass ex machina

Topicstarter
Ik heb in ASP wat zitten oefenen met Regular expressions, bijv. om URL's en emailadressen binnen tekst te herkennen en om te zetten naar <A>, en om UBB-style tags te converteren. Probleem daarbij is dat het probeerbestand wat ik heb geschreven een beetje raar doet.

De expressies heb ik allemaal op eenzelfde manier geschreven, maar de ene Reg.exp doet het gewoon goed, terwijl anderen alleen de eerste match vinden, of zelfs helemaal geen. Bij allen staat Regexp.Global = True.

mijn vrij simpele oefenbestandje ziet er als volgt uit:
ASP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<%
Dim Input, Output1, Output2, Output3, Output4, Output5, Output6, FindURL, 
FindB, FindURLtag, FindI, FindU, FindMail

Input = "blabla cool[url=http://www.planetp01nt.com]Planet P01nt website[/url]
 blabloe piet@jan.com we are testing the [u]replacing methods[/u] using [i]regular
 expressions[/i] which are extremely fucking cool dude! [b]woohooo![/b] [u]out[i]in
[/i]out[/u] some sample urls: http://www.dood.com supersimon33@hotmail.com [u]
under lined[/u] [b]more bold[/b] adumbuser@inter.net jawel,
[url=http://www.planetcrap.com]dit is een buttsite[/url]. en dit al helemaal:
 [url=http://www.powerunlimited.nl]PU site[/url]"

Set FindMail = New RegExp
'zoekt naar strings met een @ erin, en een punt met daarna 2 of 3 letters aan
'het eind (domeinextensie)
With FindMail
    .Pattern = "(\b[\w]+@[\w]+.[\w]{2,3})"
    .Global = True
    .IgnoreCase = True
End With

Set FindB = New RegExp
'zoekt naar [b] [/b] tags
With FindB
    .Pattern = "\\[b\]([^\\[/b\]]+)\\[/b\]"
    .Global = True
    .IgnoreCase = True
End With

Set FindU = New RegExp
'zoekt naar [u] [/u] tags
With FindU
    .Pattern = "\\[u\]([^\\[/u\]]+)\\[/u\]"
    .Global = True
    .IgnoreCase = True
End With

Set FindI = New RegExp
'zoekt naar [i] [/i] tags
With FindI
    .Pattern = "\\[i\]([^\\[/i\]]+)\\[/i\]"
    .Global = True
    .IgnoreCase = True
End With

Set FindURLtag = New RegExp
'zoekt naar [url=http://www.site.com]site[/url] tags
With FindURLtag
    .Pattern = "\\[url=(http://[^ \]]+)\]([^\\[]+)\\[\/url\]"
    .Global = True
    .IgnoreCase = True
End With

Set FindURL = New RegExp
'zoekt naar url's beginnend met http:\\
With FindMail
    .Pattern = " http:\/\/([^ @]+)"
    .Global = True
    .IgnoreCase = True
End With

Output1 = FindURLtag.Replace(Input, "<A HREF=$1>$2</A>")
Output2 = FindURL.Replace(Input, "<A HREF=$1>$1</A>")
Output3 = FindMail.Replace(Input, "<A HREF=mailto:$1>$1</A>")
Output4 = FindB.Replace(Input, "<B>$1</B>")
Output5 = FindI.Replace(Input, "<I>$1</I>")
Output6 = FindU.Replace(Input, "<U>$1</U>")

Call Response.Write(Output1 & "<BR><BR>")
Call Response.Write(Output2 & "<BR><BR>")
Call Response.Write(Output3 & "<BR><BR>")
Call Response.Write(Output4 & "<BR><BR>")
Call Response.Write(Output5 & "<BR><BR>")
Call Response.Write(Output6 & "<BR><BR>")
%>

hier is dit bestand live te aanschouwen
source in txt formaat
let alsjeblieft niet op de vage tekst in de voorbeeldstring :+ ik word een beetje baldadig als iets niet lukt.

Ik heb de resultaten van elke Reg.Exp apart gezet, zodat je makkelijk kunt zien welke het goed doen en welke minder. Alleen de FindURLtag regexp doet het perfect, maar het is mij een raadsel waarom de FindU alleen maar de eerste match vindt, en verder niks.

Zitten er fouten in mijn patterns? Of ergens anders? Bij voorbaat hartelijk dank voor hulp/advies/verbeteringen

[ Voor 19% gewijzigd door Not Pingu op 26-04-2003 21:12 ]

Certified smart block developer op de agile darkchain stack. PM voor info.


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:24

crisp

Devver

Pixelated

Het probleem zit 'm inderdaad in je expressies:
ASP:
1
.Pattern = "\\[u\]([^\\[/u\]]+)\\[/u\]"

hier gebruik je een character class, maar je wilt juist matchen op alles wat geen [./u] bevat. Ik weet ook niet of een / in ASP regexps nog een speciale betekenis heeft, want dan moet je die ook escapen ( \\[\/u\] )
Ter verduidelijking: je matched nu op een string die begint met [.u] gevolgd door een reeks characters die geen [ / u of ] bevatten, gevolgd door [./u]:
[.u]een string[./u] matched
[.u]deep blue see[./u] matched niet (string tussen [.u] en [./u] bevat een u )
(puntjes ter voorkoming van parsing hier)

[ Voor 45% gewijzigd door crisp op 27-04-2003 00:13 ]

Intentionally left blank


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 22-06 10:32

_Thanatos_

Ja, en kaal

En als je slim bent, gebruik je de (enige goeie IMO) non-greedy manier:
ASP:
1
.Pattern = "\\[u\](.+?)\\[/u\]"

日本!🎌


  • Not Pingu
  • Registratie: November 2001
  • Laatst online: 18-08 10:07

Not Pingu

Dumbass ex machina

Topicstarter
harstikke bedankt, het werkt nu :)
het valt niet mee om Reg.exps te doorgronden maar ik ben alweer wat wijzer geworden :)

ik heb nog wel 1 follow-up vraagje:

bij het replacen kun je bepaalde gedeeltes uit de matches dmv. $1, $2, etc. laten terugkomen in een string. nu zou ik graag binnen de replace method een gedeelde ($1) door een function halen.

in de string "[.code=asp] asp code hier [./code]" moeten de [code] blocks vervangen worden door <DIV>'s, en de tekst daartussen, de code zelf dus, wou ik dmv. een function opsplitsen in regels om regelnummering toe te voegen. op deze manier:
ASP:
1
2
sConvert = FindCode.Replace(sConvert, "<BR><B> $1 :</B>" _
"<DIV CLASS=" & Chr(34) & "code" & Chr(34) & ">" & CodeSplit($2) & "</DIV>")


op de normale manier lukt dat niet omdat je $1 niet aan een function kunt voeren. is er een andere manier om gedeeltes uit matches aan te spreken, en dan buiten een string?

Certified smart block developer op de agile darkchain stack. PM voor info.


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:24

crisp

Devver

Pixelated

Gunp01nt schreef op 27 april 2003 @ 18:07:
harstikke bedankt, het werkt nu :)
het valt niet mee om Reg.exps te doorgronden maar ik ben alweer wat wijzer geworden :)

ik heb nog wel 1 follow-up vraagje:

bij het replacen kun je bepaalde gedeeltes uit de matches dmv. $1, $2, etc. laten terugkomen in een string. nu zou ik graag binnen de replace method een gedeelde ($1) door een function halen.
[...]
Ik neem aan dat daar wel een manier voor is. In javascript kan je bijvoorbeeld in plaats van een replacementstring gewoon een function definieren met $1, $2 etc als parameters. PHP kent de /e modifier die de replacement eerst evalueert.
In VBscript zou ik het echter niet weten; zoek eens een goede reference, daar zal het vast wel instaan :)

Intentionally left blank


  • Not Pingu
  • Registratie: November 2001
  • Laatst online: 18-08 10:07

Not Pingu

Dumbass ex machina

Topicstarter
sorry dat ik jullie toch nog even moet lastigvallen...

het is inmiddels gelukt om matchgroups door een functie heen te halen (gewoon function("$1") ), maar waar ik me nog steeds het hoofd over breek is het matchen.

Het voorbeeld van thanatos is perfect op een ding na: het negeert linebreaks, en die wil ik nou juist wel erbij hebben. nu heb ik het halve internet afgezocht naar hoe crisp's idee uit te voeren, maar ik kom er niet achter hoe ik een hele group kan excluden. het ^ teken werkt nl. alleen voor character classes, en de tekens ? en * accepteren niet enkel 0 matches maar ook 1 of meer.

Zowel hier als hier als hier staat daar niks over in. alle references die ik heb gevonden zeggen niks over hoe je niet op een group kunt matchen.

kan iemand me helpen? :'(

[edit] ik las op een aantal asp.net gerelateerde pagina's dat (?: ) een group is die later niet teruggerefereerd kan worden, maar dit geldt alleen voor asp.net, toch?

[ Voor 9% gewijzigd door Not Pingu op 28-04-2003 16:01 ]

Certified smart block developer op de agile darkchain stack. PM voor info.


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:24

crisp

Devver

Pixelated

Een . matched inderdaad elk karakter, behalve het newline character (\n).
Ik zeg in de ASP.NET documentatie wel melding van een Singleline property, maar weet niet of die door ASP ondersteund wordt.

Mogelijke alternatieven zijn:

1) Greedy met look-ahead assertion:

"\\[b\](([^[]|\\[(?!\/b\]))*)\\[\/b\]"

2) Non-greedy, met match op . of \n:

"\\[b\]((.|\n)*?)\\[\/b\]"

disclaimer: niet getest ;)

[ Voor 13% gewijzigd door crisp op 28-04-2003 16:30 ]

Intentionally left blank


  • Not Pingu
  • Registratie: November 2001
  • Laatst online: 18-08 10:07

Not Pingu

Dumbass ex machina

Topicstarter
de non-greedy manier met (.|\n) doet de truc :) ik had zoiets al op een andere manier geprobeerd, met [.\n]+ maar dat werkte op de een of andere manier niet.

iig harstikke bedankt :)

Certified smart block developer op de agile darkchain stack. PM voor info.


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:24

crisp

Devver

Pixelated

Gunp01nt schreef op 28 april 2003 @ 16:47:
de non-greedy manier met (.|\n) doet de truc :) ik had zoiets al op een andere manier geprobeerd, met [.\n]+ maar dat werkte op de een of andere manier niet.

iig harstikke bedankt :)
Een . in een character class matched letterlijk een punt in een tekst, vandaar :)
De non-greedy manier is denk ik ook sneller, hoewel de greedy manier met look-ahead ook zou moeten werken (kan het op het moment alleen even niet testen)...

Edit: in PHP doet de 1e regexp het ook goed. Conclusie moet dus zijn dat regexps in ASP ook geen lookahead assertions ondersteunen :)

[ Voor 12% gewijzigd door crisp op 28-04-2003 23:25 ]

Intentionally left blank

Pagina: 1