Reg exp: matchen op range, maar niet op duplicaten

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 05-09 21:08
Ik wil matchen op een string van n karakters, waarin in A, B en C voorkomen, in een willekeurige volgorde (ABC, ACB, BAC etc). Ook wil ik dat iedere letter uniek voorkomt in de string.

Probleem is echter dat onderstaande expressie ook matched op AAC.

PHP:
1
preg_match_all('/[ABC]{3}/', 'ABC', $result);


Mijn vraag: kan ik met reguliere expressions uberhaupt eisen dat ieder karakter uniek moet zijn in een range? Dus hij mag niet matchen op AAB, BCB, etc.

Dit werkt in ieder geval niet:
PHP:
1
preg_match_all('/( ([ABC]) (?![ABC]) ){3}/', 'ABC', $result);

Acties:
  • 0 Henk 'm!

Verwijderd

Hiermee zou het moeten lukken
^(?:([A,B,C])(?![A,B,C]*?\1))*$

Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 05-09 21:08
Bedankt! Kleine aanpassing, zodat ie op 3 karakters checkt:

code:
1
^(?:([A,B,C])(?![A,B,C]*?\1)){3}$


Als ik de magie even probeer te ontleden:
  1. ?:([A,B,C]) matched een A, B of C als een passive group (telt niet mee als backreference)
  2. ?![A,B,C]*? zegt: na de passive group van puntje 1, mag er geen evt. duplet/triplet/etc van A,B,C voorkomen
  3. \1 is een backreferentie naar... de hele match? Dus er moet een unieke A, B, C achter komen...?
  4. {3} zegt: deze hele match moet drie keer voorkomen

Acties:
  • 0 Henk 'm!

  • Juup
  • Registratie: Februari 2000
  • Niet online
Rekcor schreef op maandag 14 maart 2011 @ 17:36:
• \1 is een backreferentie naar... de hele match? Dus er moet een unieke A, B, C achter komen...?
backreferentie naar het eerste () block

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 05-09 21:08
Juup schreef op maandag 14 maart 2011 @ 17:45:
[...]

backreferentie naar het eerste () block
Ja, dat is toch de hele match? Want daar staan ook haakjes omheen. ( (eerste blok) (tweede blok) ). Daarnaast is het eerste blok een zgn passive group.

Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
(?: is geen matchblock; \1 is 1e (), dus ([A,B,C])

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Rekcor schreef op maandag 14 maart 2011 @ 17:36:
Bedankt! Kleine aanpassing, zodat ie op 3 karakters checkt:

code:
1
^(?:([A,B,C])(?![A,B,C]*?\1)){3}$
^(?:([A,B,C])(?![A,B,C]*?\1)){3}$

Open passive block, sluit block, zeg dat deze 3x moet matchen
Match 1 A, B, of C in een block, zodat \1 er een referentie naar is.
(?: begint een negative lookahead: Match faalt als block 1 gevolgd wordt door een willekeurig aantal A's, B's, of C's en eenzelfde karakter als gematched in block 1. Het vraagteken na de * zorgt voor een ungreedy match.

Moest hier ook even naar kijken, en zou het zelf niet met een enkele regex doen. Als je het opsplitst in de volgende fouten: ongeldige lengte, ongeldige karakters, dubbele karakters krijg je een drietal triviale condities. Leest imo lekkerder, user friendly, debug friendly. :)

Of in dit geval kan je ook gewoon ff alle 6 permutaties hardcoden. :+

{signature}


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Wat doen die komma's in die character class? :o

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 05-09 21:08
Voutloos schreef op maandag 14 maart 2011 @ 22:36:
[...]

^(?:([A,B,C])(?![A,B,C]*?\1)){3}$

Open passive block, sluit block, zeg dat deze 3x moet matchen
Match 1 A, B, of C in een block, zodat \1 er een referentie naar is.
(?: begint een negative lookahead: Match faalt als block 1 gevolgd wordt door een willekeurig aantal A's, B's, of C's en eenzelfde karakter als gematched in block 1. Het vraagteken na de * zorgt voor een ungreedy match.
Dank je! Op deze manier leer ik er hopelijk wat van :).
Voutloos schreef op maandag 14 maart 2011 @ 22:36:
[...]

en zou het zelf niet met een enkele regex doen. Als je het opsplitst in de volgende fouten: ongeldige lengte, ongeldige karakters, dubbele karakters krijg je een drietal triviale condities. Leest imo lekkerder, user friendly, debug friendly. :)

Of in dit geval kan je ook gewoon ff alle 6 permutaties hardcoden. :+
Probleem is dat de reg exp in werkelijkheid in een stuk XML staat, dat in een object wordt gestopt, en waar ik niets aan kan/wil veranderen (tenminste, ik kan de class natuurlijk forken, maar dan moet ik betreffende library vervolgens zelf gaan onderhouden etc).

Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 05-09 21:08
@NMe: goed punt, dank

code:
1
^(?:([ABC])(?![ABC]*?\1)){3}$

Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
btw, RegexBuddy kan regular expressions "uitleggen" zoals Voutloos dat deed.

Afbeeldingslocatie: http://www.download.ba/proimg/RegexBuddy-20100610-140917.png

Erg handig

[ Voor 27% gewijzigd door Gamebuster op 15-03-2011 12:57 ]

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Zou nog handiger zijn als het gewoon webbased en gratis was. :P

{signature}

Pagina: 1