[php] eregi_replace vraag

Pagina: 1
Acties:
  • 640 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

Anoniem: 12517

Topicstarter
Hallo,
Ik heb voor een klant php scripts gemaakt waarbij hij content kan wijzigen op de site. Nu heb ik wat ubb-achtige codes erin gezet.

Er kunnen er interne links worden gemaakt naar database bestanden met de vorm content.php?id=1, dit in de vorm [n=1]hier klikken[/n], dit doe ik zo:
PHP:
1
2
3
<?
$text = eregi_replace("\\\[n=([^\\\[]*)\\]([^\\\[]*)\\\[/n\\]","<a href=\"content.php?id=\\1\">\\2</a>",$text);
?>

Dit werkt prima, alleen het terugconverteren (als hij dus de content weer wil veranderen) lukt soms niet, zo doe ik dat:
PHP:
1
2
3
<?
$text = eregi_replace("<a href=\"content.php\?id=([^\\\[]*)\">([^\\\[]*)</a>","\\[n=\\1]\\2[/n\\]",$text);
?>

Nu wil 'ie soms wel en soms niet terugconverteren, kunnen jullie zien waarom??

Thanx

Acties:
  • 0 Henk 'm!

Anoniem: 12517

Topicstarter
Zou het kunnen liggen aan te lange zinnen tussen <a> en </a>???

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Heb je je regexen zelf gemaakt? Uiteraard perfect in dat geval, maar ik vind ze nogal onlogisch in elkaar zitten :?

Waarom de
code:
1
[^\\\[]*

wanneer ik het idee heb dat je iets als
code:
1
.*

bedoelt? Ik niet goed snappen...

Acties:
  • 0 Henk 'm!

Anoniem: 12517

Topicstarter
Ik heb ze zelf geschreven, maar ook wat afgekeken bij bestaande code. Het veranderen van [^\\\[]* in .* is inderdaad logischer.
Jammer is nu, dat ik precies dezelfde fouten krijg met deze nieuwe methode. Als ik deze link (<a href=content.php?id=1>dit is een link</a>) terugconverteer krijg ik netjes:

[n=1]dit is een link[/n]

Maar als ik meerdere links achter elkaar zet pakt 'ie de eerste wel [n=1], vervolgens veranderd ie de html codes niet en de laatste link word weer afgesloten met een [/n]. Ik ben geen held in regexen, maar ik kan de fout niet vinden... iedere suggestie wordt gewaardeerd :)

Acties:
  • 0 Henk 'm!

Anoniem: 15403

Volgens mij heb je nu op een omslachtige manier het woord greedy omschreven :)

Greedy = hij pakt ipv alle instants samen (dus [n]..[/n] .. [n]..[/n] alleen de voorste [n] en de achterste [/n] en de rest er tussen] alle instants apart (dus [n]..[/n] .. [n]..[/n] allebei). Natuurlijk komt het van het engelse greedy, dat betekent hebberig/gulzig (etc) en d'r wordt dus mee bedoelt dat de parsser gulzig is en alles in een keer wilt.

Natuurlijk is er behalve de therorie ook nog een oplossing >:) en wel als volgt:
PHP:
1
2
3
<?
$string = preg_replace("!\[n=(.*)\](.*)\\[/n\]!Uis", "<a href=\"\\1">2</a>", $string);
?>

Hoe werkt dit dan?
Ten eerste maak ik gebruik van een Perl Compitable Regular Expression (pregex dus :)), dat geeft je een scala aan extra mogelijkheden. Nu heb ik de modifiers Uis toegevoegd, de U is om greedy op te heffen, de i om het caseless te maken en de s om . ook als spatie te laten tellen. Voor meer info hierover kan je kijken op: Regular Expressions.

Het terug converteren kan je nu waarschijnlijk zelf wel verzinnen..

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Of lees deze thread ook even door:

[topic=161280]

Acties:
  • 0 Henk 'm!

Anoniem: 12517

Topicstarter
Het is allemaal gelukt, dank je wel dannydude voor de duidelijke uitleg. Weer een stapje verder in m'n php kennis.

O ja, terugconverteren heb ik nu zo gedaan:
PHP:
1
2
3
<?
$text = preg_replace("!<a href=\"content\.php\?id=(.*)\">(.*)</a>!Uis","\\[n=\\1]\\2[/n\\]",$text);
?>

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Op woensdag 13 juni 2001 21:07 schreef Anchorman het volgende:
dank je wel dannydude voor de duidelijke uitleg.
Alleen jammer dat een aantal dingen niet helemaal klopten :+

Zal als ik tijd heb misschien eventjes een paar verbeteringetjes neerzetten. No offence verder, alleen maar goed als iemand iets uitlegt.

Acties:
  • 0 Henk 'm!

Anoniem: 15403

:+ , ik voel me niet zo gauw offenced hoor, ik PHP ook nog niet eens een jaar...
ben wel benieuwd wat er fout is!

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Op woensdag 13 juni 2001 20:39 schreef dannydude het volgende:
Greedy = hij pakt ipv alle instants samen (dus [n]..[/n] .. [n]..[/n] alleen de voorste [n] en de achterste [/n] en de rest er tussen] alle instants apart (dus [n]..[/n] .. [n]..[/n] allebei).
Volgens mij bedoel je het andersom :)
[..] en d'r wordt dus mee bedoelt dat de parsser gulzig is en alles in een keer wilt.
Kleine verduidelijking: het is niet de 'parser' (ook niet zo'n mooie woordkeuze, maar goed) die greedy is, maar de quantifier. Quantifier 1 kan dus best ungreedy zijn, terwijl quantifier 2 greedy is (in hetzelfde pattern).
Natuurlijk is er behalve de therorie ook nog een oplossing >:) en wel als volgt:
PHP:
1
2
3
<?
$string = preg_replace("!\[n=(.*)\](.*)\\[/n\]!Uis", "<a href=\"\\1">2</a>", $string);
?>
Ga je dus wel uit van PCRE en er zijn vaak meerder oplossingen. In dit geval is ungreedy maken voor 1 van de twee quantifiers wel de enige echt goede oplossing.
de U is om greedy op te heffen
Nee, het wisselt de default 'greedyness-state' van alle quantifiers. Een ? wisselt deze altijd om, dus het gebruik van een ? zou in dit geval een quantifier weer greedy maken.
en de s om . ook als spatie te laten tellen.
Nee, om ook newlines te matchen :)
Spaties worden toch wel gematched.
Voor meer info hierover kan je kijken op: Regular Expressions.
Of voor (voor PHP aangepaste) PCRE docs: http://www.php.net/pcre
En voor POSIX regexen binnen PHP uiteraard: http://www.php.net/regex

Paar kleine verbeteringen ;)

Acties:
  • 0 Henk 'm!

Anoniem: 15403

Je hebt (natuurlijk) gelijk, het meeste wist ik wel, maar een paar dingetjes erbij geleerd, tnx

Acties:
  • 0 Henk 'm!

  • brammetje
  • Registratie: Oktober 2000
  • Laatst online: 12-01 11:31
Op woensdag 13 juni 2001 22:36 schreef tomato het volgende:
Kleine verduidelijking: het is niet de 'parser' (ook niet zo'n mooie woordkeuze, maar goed) die greedy is, maar de quantifier. Quantifier 1 kan dus best ungreedy zijn, terwijl quantifier 2 greedy is (in hetzelfde pattern).

[..]

Nee, het wisselt de default 'greedyness-state' van alle quantifiers. Een ? wisselt deze altijd om, dus het gebruik van een ? zou in dit geval een quantifier weer greedy maken.
hmmz..

zou je dit met enige voorbeeldjes kunnen uitlichten??

snap het niet helemaal eerlijk gezegd..

Acties:
  • 0 Henk 'm!

  • tomato
  • Registratie: November 1999
  • Niet online
Op woensdag 13 juni 2001 22:43 schreef dannydude het volgende:
Je hebt (natuurlijk) gelijk, het meeste wist ik wel, maar een paar dingetjes erbij geleerd, tnx
Dacht ook wel dat je het meeste eigenlijk wist, alleen even op de juiste manier verwoorden ;)
Op woensdag 13 juni 2001 22:47 schreef PlayR het volgende:
zou je dit met enige voorbeeldjes kunnen uitlichten??
Okay, zal proberen het principe greedyness wat toe te lichten :)

Ik ga even uit van perl regexen.

Laten we als voorbeeld de volgende string nemen:
code:
1
aababbaaaa

Wanneer we daar het volgende pattern op los laten
code:
1
/ba*/

zul je de volgende match terug krijgen:

aababbaaaa

Wanneer we hem global maken
code:
1
/ba*/g

Zullen we de volgende matches terug krijgen:

aababbaaaa
aababbaaaa
aababbaaaa

(Dit kan ik niet tussen code tags zetten, want dan werkt de bold tag niet meer...)

Er wordt dus bij het zoeken naar een match eerst gekeken naar de vroegst mogelijke match (van links naar rechts) en dan pas naar mogelijkheden om die match zo lang mogelijk te maken. Dit laatste verklaart waarom je in je eerste match ba terug krijgt en niet gewoon b of baaaa (dit zouden immers ook al een geldige match zijn). Dit wordt greedyness genoemd. In dit geval is de quantifier * dus greedy.

Nu maken we de quantifier ungreedy (greedyness toggle je door een vraagteken achter de quantifier te zetten):
code:
1
/ba*?/g

Resultaten zullen nu zijn:

aababbaaaa
aababbaaaa
aababbaaaa

Geen verschil dus :) . Maar dat klopt ook. Legde ik een stukje terug het proces uit van het vinden van matches met een greedy quantifier, hier de regels bij een ungreedy quantifier:

Eerst wordt er gezocht naar de vroegst mogelijke match (van links naar rechts) en dan pas naar mogelijkheden om die match zo lang mogelijk te maken. Maar, dit laatste wordt niet gedaan als er hierdoor andere mogelijkheden tot matchen verloren gaan. Voorop staat dus het vinden van zo veel mogelijk matches, dan pas het zo lang mogelijk maken van deze matches!

Het verschil tussen greedy en ungreedy kun je wel met het volgende patterns zien:
code:
1
/b.*/g

Resultaten bij greedy quantifier:

aababbaaaa
code:
1
/b.*?/g

Resultaten bij ungreedy quantifier:

aababbaaaa
aababbaaaa
aababbaaaa


Default zijn quantifiers greedy. Voorbeelden van quantifiers zijn:

*
+
?
{n,m}

Wanneer je de U (ungreedy) modifier gebruikt, worden alle quantifiers in je pattern default ungreedy:
code:
1
/b.*/U

is dus hetzelfde als
code:
1
/b.*?/

En
code:
1
/b.*?/U

is dus hetzelfde als
code:
1
/b.*/

Ik hoop dat het een en ander nu iets duidelijker is :)

Als ik wat dingen vergeten ben of verkeerd heb ga ik er natuurlijk vanuit dat ik aangevuld/verbeterd wordt.

Acties:
  • 0 Henk 'm!

Anoniem: 11648

tomato: Volgens mij bedoel je het andersom :)

Begrijp je dan wat hij hiermee bedoelt? :? (Ik niet namelijk.)
Greedy = hij pakt ipv alle instants samen (dus [n]..[/n] .. [n]..[/n] alleen de voorste [n] en de achterste [/n] en de rest er tussen] alle instants apart (dus [n]..[/n] .. [n]..[/n] allebei).
Kleine verduidelijking: het is niet de 'parser' (ook niet zo'n mooie woordkeuze, maar goed) die greedy is, maar de quantifier.

Kleine verduidelijking ;) : het is niet de quantifier die greedy is, maar de regex-egnine (die greedy gemaakt wordt).

[ /U ] wisselt de default 'greedyness-state' van alle quantifiers. Een ? wisselt deze altijd om, dus het gebruik van een ? zou in dit geval een quantifier weer greedy maken.

Wizziknie :o (Is ook niet Perl-compatible dus niet belangrijk :P )

Acties:
  • 0 Henk 'm!

Anoniem: 11648

tomato: Er wordt dus bij het zoeken naar een match eerst gekeken naar de vroegst mogelijke match (van links naar rechts) en dan pas naar mogelijkheden om die match zo lang mogelijk te maken.

Aanvulling: Greediness bepaalt hoeveel er gematcht wordt en niet waar.

Dit laatste verklaart waarom je in je eerste match ba terug krijgt en niet gewoon b of baaaa (dit zouden immers ook al een geldige match zijn).

Aanvulling: het (overall) doel van de regex-engine is het vinden van een match in een string, niet het vinden van de langste match in een string.

Resultaten zullen nu zijn. [...]

Ehm, nee... sorry :) Voor /ba*?/ is 0 keer een a genoeg. Misschien dat minimal (of desnoods: lazy) en maximal betere namen zijn dan ungreedy en greedy.

De verbeteringen staan in deze samenvatting (matches binnen [..]):
code:
1
2
3
4
5
6
7
GREEDY:
/ba*/g;    macthes: aa[ba][b][baaaa]
/b.*/g;    match:   aa[babbaaaa]

ungreedy, lazy, MINIMAL:
/ba*?/g    macthes: aa[b]a[b][b]aaaa
/b.*?/g    macthes: aa[b]a[b][b]aaaa

Ik denk dat het idee in ieder geval nu wel duidelijk is. :)

Acties:
  • 0 Henk 'm!

Anoniem: 15403

Op Saturday 16 June 2001 09:11 schreef Arien het volgende:
Begrijp je dan wat hij hiermee bedoelt? :? (Ik niet namelijk.)
[..]
[...]
ik zal het nog even nader toelichten, ik wilde er even makkelijk mee uitleggen, wat jullie zeiden met dat ba-voorbeeld.
(dus [n]..[/n] .. [n]..[/n] alleen de voorste [n] en de achterste [/n] en de rest er tussen) dit is dus als hij bij [n]blaat[/n]blaat[n]blaat[/n] alleen de dikgemaakte tags pakt en alles ertussen in als het subpattern. (\\1)

(dus [n]..[/n] .. [n]..[/n]) hier pakt ie bij [n]blaat[/n]blaat[n]blaat[/n] dus alle instants apart...

snap je nu wat ik bedoelde

PS: je bent weer back :)

edit: de quote-ubb wil niet echt werken...

Acties:
  • 0 Henk 'm!

Anoniem: 11648

dannydude: Snap je nu wat ik bedoelde?

Ik snap hem ja.

PS: je bent weer back :)

Minder dan het lijkt...
Pagina: 1