[megoldva] Regexp - karakterosztály és szekvencia

Egy HTML tartalmat kell validálnom, rendezett lista formában.

Viszonylag kötött kinézet, de a felsorolásban tetszőleges szöveg lehet. A tartalmon belül viszont csak <br>, <em> és <strong> tag-ek, semmi egyéb formázás, css vagy bármi.

Talán számít, hogy MaraiDB-ben szeretném ezt megvalósítani, és nem kéne egymásba ágyazni függvényeket.

Jelenleg így néz ki a kifejezés, de ez nyilván nem engedi a TAG-ek használatát:

'^<ol>\\s*(\\s*<li>[a-z0-9\#\&\@\{\}\(\)\[\]\:\;\,\.\-\'\"\+\!\?\%\/\=öüóőúéáűí\s]+</li>\\s*)+\\s*</ol>$'

Amivel próbálkoztam, de elestem a tudatlanságom miatt. Az ötlet az volt, hogy egy tetszőleges karakterre illeszkedik az osztály, vagy a tag-ekre, és ezek egyben legalább egyszer előforduljanak a lista tagjaként:

'^<ol>\\s*(\\s*<li>(([a-z0-9\#\&\@\{\}\(\)\[\]\:\;\,\.\-\'\"\+\!\?\%\/\=öüóőúéáűí\s])|(<br>)|(<em>)|(</em>)|(<strong>)|(</strong>))+</li>\\s*)+\\s*</ol>$'

Összefoglalva tehát valahogy karakter osztályba kellene szekvenciát belekevernem. Kérem, aki tud, segítsen!

Hozzászólások

'^\\s*<ol>\\s*(<li>([^<]+|</?(br|em|strong)>)*</li>\\s*)+</ol>\\s*$'

Ez kb. az, amit szeretnél, de nem érdekli, hogy <em> és <strong> esetén van-e nyitó tag a lezáróhoz (vagy van-e egyáltalán lezáró) és nem érti a <br/> taget, viszont a </br>-t igen. Az utóbbi, br-t érintő probléma még könnyedén megoldható:

^\\s*<ol>\\s*(<li>([^<]+|<(br/?|/?(em|strong))>)*</li>\\s*)+</ol>\\s*$

(A tiédet bevallom, meg sem próbáltam végigellenőrizni, túl sok nekem benne a backslash és a zárójel, de látszólag majdnem eltaláltad, csak kissé túlbonyolítottad.)

miben jobb, mint az enyém, azt nem teljesen értem

Erősen olyan érzésem van, hogy ez egy kezdeti próbálkozásod a regexszel. Idővel kialakulnak majd azon reflexeid, hogy próbálj minél tömörebben fogalmazni.

Ha kigyalulom a backslasheket, és nem érdekel, hogy az adott nyelven a string literal milyen spec jelöléseket ismer, ez marad:

^<ol>\s*(\s*<li>(([a-z0-9#&@{}()[\]:;,.-'"+!?%/=öüóőúéáűí\s])|(<br>)|(<em>)|(</em>)|(<strong>)|(</strong>))+</li>\s*)+\s*</ol>$

Az első, ami szembetűnő, hogy az osztály felesleges korlátozásokat vezet be, illetve van benne egy konkrét hiba: a - mindig az utolsó, ha nem akarod, hogy tartományt jelöljön. (Pl. simán lehet, hogy ez volt a problémád, nem más speciális karakter.)

A feladatot te magad szabtad meg: ne szerepelhessen bármilyen tag. A leírásnál is kövesd ezt: ne szerepelhessen bármilyen tag. Szóval a legegyszerűbb, ha bármi szerepelhet, csak tag nem, ami mégis, azt majd alternate-tel megcsinálod. Ezért simán illeszthetsz mindenre, ami nem <.

A másik, iszonyatosan nehezen felismerhető problémákhoz vezető dolog, ha ugyanaz a minta többféleképpen illeszkedhet ugyanarra a szövegre. A te mintád ezen része egyszerűsítve:

^\s*(\s*X\s*)\s*$

Házi feladat: a fenti minta hányféleképpen illeszkedik a következő szövegre? " X "

Az én megoldásomban – lustaságból – végig sima zárójeleket használtam, de ilyen esetben általában végig (?:)-ot használnék, hiszen nincsen szükségem később a tartalmukra (többmilliós iterációknál ez azért számít). Zárójelet feleslegesen soha ne használj!

Ha kell a zárójelen belüli tartalom később, akkor döntsd el, hogy ws-ekkel együtt vagy sem, de ha lehet, a minta ne tudjon többféleképpen illeszkedni.

Az alternate-ek: Amíg 1-2 tételed van, nem tűnik macerásnak, hogy kiírod a nyitó és záró taget is, de nem véletlen nem tettem. Sokkal egyszerűbb, és a regex kifejezetten kínálja a lehetőséget: ha a zárást egy / jelzi az elején, akkor bármelyik tag jó, függetlenül attól, van-e előtte /. Akkor ne írjuk ki kétszer a taget, egyszer nyitó, egyszer záró formában, legyen előtte a /? .