[PHP] Regexp op niet-escapete haakjes.

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
Ik krijg van een programma een regel met daarin een aantal sleutelwoorden met daarachter tussen haakjes een waarde. Wanneer die waarde een haakje bevat, is die vooraf gegaan door een slash. Voorbeeldje:
code:
1
$line = 'id(3) name(test\(1 van 2\).film)';

Die wil ik met preg_match_all in 1 keer splitten naar sleutels met waarden (dus 'id' bij '3', en 'name' bij 'test (1 van 2).film').
Nu geeft het haakje-met-slash-ervoor problemen. Ik heb al een boel geprobeerd en dit leek me het meest in de buurt van een goede oplossing komen:
code:
1
preg_match_all('/([a-zA-Z]*)\((.*?)[^\\]\)/', $line, $info);

uitleg:
([a-zA-Z]*) matcht de sleutel.
\((.*?) matcht haakje openen en de zooi erachter (un-gready, dus het eerste haakje dat hij vindt).
[^\\]\) zou dan niet-slash gevolgd door een haakje moeten vinden. PHP kan dan echter geen 'terminating ]' vinden, dus hij denkt dat ik de vierkante haakje heb geescaped.

Zonder geescapede haakjes en zonder [^\\] werkt het prima. Wie kan me helpen?

[ Voor 5% gewijzigd door ajvdvegt op 15-01-2003 13:25 ]

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

doe es echo '[^\\]';

dan zie je wel wat je fout doet :)
preg_match krijgt het _zo_ binnen als het afgedrukt wordt, niet zo als je het intikt :)

Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
Als ik echo '[^\\]'; doe, krijg ik [^\] te zien. Dat is precies wat ik verwacht: ik wil op niet-slash met haakje sluiten matchen.
Maar als preg_match_all het idd zo binnenkrijgt, dan zou er nog een dubbele slash bij moeten, omdat nu idd de ] wordt geescapet. Maar je raad het al, dat werk ook niet.

<update>
GEVONDEN: nog een enkele slash toevoegen! de juiste expressie:

preg_match_all('/([a-zA-Z]*)\((.*?)[^\\\]\)/', $line, $info);

<update2>
Hmm, toch nog net niet helemaal perfect: het laatste teken voor het haakje sluiten wordt niet meegenomen nu. Maar ik zal vanavond eens gaan kijken naar voorwaarden in regexpen (ala (?=\\\)\) ofzo.)

[ Voor 22% gewijzigd door ajvdvegt op 15-01-2003 10:12 ]

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum


Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
Hmm, na een edit kom je niet boven te staan, dus even een beetje helpen... sorry.

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 08:51

Janoz

Moderator Devschuur®

!litemod

Ook daarvoor geldt waarschijnlijk precies hetzelfde. Druk de gehele string eens af?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

Verwijderd

Een enkele backslash zul je moeten aangeven met vier bakslashes.
Twee slashes worden door PHP vervangen voor ééb backslash in de string. Die ene backslash zorgt ervoor dat de ] in het pattroon escapet wordt, en dat wil je niet. In je patroon wil je dus inderdaad nóg een backslash, die je dus weer met twéé backslashes zult moeten aangeven in de string.

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

[nohtml]
ajvdvegt schreef op 15 January 2003 @ 09:19:
Als ik echo '[^\\]'; doe, krijg ik [^\] te zien. Dat is precies wat ik verwacht: ik wil op niet-slash met haakje sluiten matchen.
Maar als preg_match_all het idd zo binnenkrijgt, dan zou er nog een dubbele slash bij moeten, omdat nu idd de ] wordt geescapet. Maar je raad het al, dat werk ook niet.
Das idd precies wat je zou verwachten :)
Maar de \ is een metacharacter dus die moet je voor de regexp ook escapen. Maar voor de regexp moet het [^\\] zijn. Als je dat dan terug redeneert ,wetende dat elke \ een metacharacter is, in zowel een regexp als in een text-string, zou je elke \ door \\ moeten vervangen voor de regexp en elke \ door \\ voor de textuele string, dubbelop dus.

[ Voor 3% gewijzigd door ACM op 15-01-2003 12:51 ]


Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
Goed, het escapen is nu (meer) duidelijk. Al maak het niet uit of ik drie of vier slashes gebruik:
code:
1
2
preg_match_all('/([a-zA-Z]*)\((.*?)[^\\\\]\)/', $line, $info);
preg_match_all('/([a-zA-Z]*)\((.*?)[^\\\]\)/', $line, $info);

Geven precies hetzelfde resultaat, namelijk dit:
code:
1
2
id -> 
name -> test\(1 van 2\).fil

M.a.w., het laatste teken voor het correcte haakje wordt niet meegenomen.

Mijn tweede poging is dit:
code:
1
preg_match_all('/([a-zA-Z]*)\((.*?)(?=\\\\)\)/', $line, $info);

Maar als ik in (?=\\\\) drie of vier slashes zet, krijg ik helemaal geen match, en bij twee of meer dan vier krijg ik errors over 'missing )'. 8)7

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

code:
1
preg_match_all('/([a-zA-Z]*)\\\(([^\\\\]*?)\\\)/', $line, $info);

en zoiets?
of zo:
code:
1
preg_match_all('/([a-zA-Z]*)\\\((.*?)[^\\\\]\\\)/', $line, $info);

Sowieso vergat je nog expliciet op de \ voor de ( te zoeken (de \ voor de ( in jouw regexp's was voor het escapen van de speciale functie van de ( :) )

Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
ACM schreef op 15 January 2003 @ 13:48:
code:
1
preg_match_all('/([a-zA-Z]*)\\\(([^\\\\]*?)\\\)/', $line, $info);

en zoiets?
of zo:
code:
1
preg_match_all('/([a-zA-Z]*)\\\((.*?)[^\\\\]\\\)/', $line, $info);

Sowieso vergat je nog expliciet op de \ voor de ( te zoeken (de \ voor de ( in jouw regexp's was voor het escapen van de speciale functie van de ( :) )
Nee hoor, die eerste \ vergat ik niet. Voor het eerste haakje-openen staat namelijk geen slash.
Als ik jouw codes bekijk lijkt het alsof je juist wil matchen op een slash met een haakje, en voor DIE slash weer geen slash, zodat \\) niet goed is, en \) wel.
Ik wil dus juist enkel ) matchen, en niet \). :)

Kan ik niet op een of andere manier een ander escape-teken opgeven ofzo? In Perl kan dat wel geloof ik.

[ Voor 26% gewijzigd door ajvdvegt op 15-01-2003 13:59 . Reden: verkeede knop..... ]

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Ik keek idd verkeerd :)

code:
1
preg_match_all('/([a-zA-Z]*)\((.*?)(?!\\\\)\)/', $line, $info);

Doet dat wel wat je wil?

Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
Nee, die matcht weer gewoon het eerste haakje dat-ie tegenkomt. :'(

(?!foo)bar matcht toch op elke 'bar' die NIET wordt voorgegaan door 'foo'? Ik wil nu juist WEL een 'foo' (een slash dus bij mij). Daaro dus mijn (?=foo)bar poging.

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

ajvdvegt schreef op 15 January 2003 @ 15:22:
Nee, die matcht weer gewoon het eerste haakje dat-ie tegenkomt. :'(

(?!foo)bar matcht toch op elke 'bar' die NIET wordt voorgegaan door 'foo'? Ik wil nu juist WEL een 'foo' (een slash dus bij mij). Daaro dus mijn (?=foo)bar poging.
foo(?!bar)

matches any occurrence of "foo" that is not followed by
"bar". Note that the apparently similar pattern

(?!foo)bar

does not find an occurrence of "bar" that is preceded by
something other than "foo"; it finds any occurrence of "bar"
whatsoever, because the assertion (?!foo) is always TRUE
when the next three characters are "bar". A lookbehind
assertion is needed to achieve this effect.
bron: http://www.php.net/manual/en/pcre.pattern.syntax.php

Je moet dus met lookbehind gaan werken:
code:
1
(?<!foo)bar

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • ajvdvegt
  • Registratie: Maart 2000
  • Laatst online: 13-08 16:01
crisp, JIJ bent geweldig. Ik had dat stuk gisteren ook gelezen, maar toen ging ik de mist met de slashes. Het werkt nu echt helemaal goed, dank u allen hartelijk!

Voor 't archief nog even de hele opdracht:
code:
1
preg_match_all('/([a-zA-Z]*)\((.*?)(?<!\\\\)\)/', $line, $info);

I don't kill flies, but I like to mess with their minds. I hold them above globes. They freak out and yell "Whooa, I'm *way* too high." -- Bruce Baum

Pagina: 1