[PHP/RegExp] Der RegExp-Übungsthread

theHacker

sieht vor lauter Ads den Content nicht mehr
Teammitglied
ID: 69505
L
20 April 2006
22.680
1.315
Irgendwie is mein alter Thread schon wieder weg :ugly: :-?

Mittlerweile bin ich schon ganz gut mit den Dingern :D
Konkret arbeite ich gerade an dem hier:
Code:
/^((?:\d+)(?:[,.]\d{2})?)(?:\s?€)?$/
Meine Frage dazu: Wie schaffe ich es, dass mir preg_match() fehlschlägt, wenn man nach dem Komma nicht genau 2 Ziffern dahinter setzt ?

P.S. für die, die gern raten wollen, hab ich nicht hingeschrieben, für was der RegExp eigentlich ist.
 
Prüft eine Preisangabe auf Gültigkeit?
Und eigentlich würde ich erwarten dass das so funktioniert...
 
Xgame schrieb:
Prüft eine Preisangabe auf Gültigkeit?
Und eigentlich würde ich erwarten dass das so funktioniert...
Irgendwie ... :think: ... hab ich nachträglich die ^...$ eingefügt, das nicht getestet, sondern den Code hier gleich gepostet.
Ja, er funktioniert :oops: :dance:

Ohne ^...$ hätte er nämlich auch "56,565" zugelassen, weil dann (?:[,.]\d{2})?) nicht gegriffen hat.

Ok, auch gut, geht :D
Kann ich daran noch was verbessern ? Oder is der schon perfekt ?
 
Die zweite Subklasse ist imo überflüssig, aber ob das was ausmacht...
Code:
/^(\d+(?:[,.]\d{2})?)(?:\s?€)?$/
 
Die inneren Groupings sind eh alle überflüssig, da sie halt nicht gecaptured werden.

[edit]

Wupps, die Klammerung falsch gelesen. Hab nix gesagt... :sing:
 
Nun, da ich auch gerade einmal am Üben bin, hier mein Problem:

$newtext=preg_replace("#\[b\](.*)\[/b\]#iU", "<span style=\"font-weight: bold;\">\1</span>",$newtext);


Das funktioniert zwar, aber ich manchmal irgendwie nicht. Ich weiß aber nicht wieso. Es geht zum Beispiel nicht, wenn zwei B-Tags gesetzt sind... also ein Bold-Text innerhalb eines Anderen.
Aber irgendwie funktionert es wohl auch nicht immer, wenn eine neue Zeile dazwischen liegt.

Zum Beispiel hier:
https://www.wilde-jungs.net/artikel.php?id=16

Nur was ist der Fehler? Wieso wird es manchmal nicht richtig angezeigt? Könnt ihr mir da helfen? Was muss ich ändern?

Wäre echt nett!

-Flori-
 
@ thehacker..
im prinzip find ichs ok (von den vielen klammern abgesehn), will nur mal eines loswerden :)..
wenn du \s verwendest sind auch zeilenumbrüche erlaubt, will man das nun 100%-ig machen, würde man an solch einer stelle maximal leerzeichen zulassen aber keine tab's, newlines, usw..

*nur als idee
 
Scar schrieb:
@ thehacker..
[...]
wenn du \s verwendest sind auch zeilenumbrüche erlaubt, will man das nun 100%-ig machen, würde man an solch einer stelle maximal leerzeichen zulassen aber keine tab's, newlines, usw..
Das is ja mein Ziel: 100%ig perfekt zu werden :D

Danke für den Einwand. Da sollen natürlich nur Leerzeichen erlaubt sein.
Kann ich im Pattern dann einfach ein Leerzeichen setzen oder muss ich \x20 verwenden ? Ich hab mich eigentlich auf das
\s
a
ny whitespace character
verlassen.
 
wenn du kein x als modifier verwendest kannst du locker auch einfach ein leerzeichen schreiben, also ' *' (müsste klappen)
 
evident schrieb:
Das funktioniert zwar, aber ich manchmal irgendwie nicht. Ich weiß aber nicht wieso. Es geht zum Beispiel nicht, wenn zwei B-Tags gesetzt sind... also ein Bold-Text innerhalb eines Anderen.
Naja ist doch klar, stelle dir mal als Ausgangstext folgendes vor:
Eins[b]zwei[b]drei[/b]vier[/b]
Das sieht nach dem Ersetzen so aus:
Eins<b>zwei[b]drei</b>vier[/b]
Liegt daran, dass nach dem Fund des Start-Tags alle folgenden Start-Tags ignoriert werden, bis das passende End-Tag gefunden wird.

Ich würde behaupten, will man Verschachtelungen korrekt handeln, kommt man mit Regexp alleine nicht weiter.

Gruß,
Xgame
 
Ja so dachte ich mir das auch schon...

Aber wäre es möglich, dass er per RegExp guckt, ob weitere Starttags drin sind, und dann jeweils erst den zweiten End-Tag zurückübersetzt?

Oder soll ich einfach das Ding mehrmals durchlaufen lassen? Weil dann würde er beim zweiten Durchlauf zum Beispiel die restlichen beiden B-Tags sehen und parsen. Aber ich weiß nicht, ob das wirklich effektiv wäre... :D
 
Mehrmals laufen lassen wird in diesem Fall wohl zum "gewünschten" Ergebnis führen, aber ist meiner Meinung nach sehr unelegant.
Man stelle sich folgendes vor:
Code:
[PLAIN][list]
[*]Blabla
[*]Foobar
[*]Lalala
[list=1]
[*]Lalala 1
[*]Lalala 2
[/list]
[*]Dummy
[/list][/PLAIN]
Das erste [list]-Tag sollte hier durch <ul> ersetzt werden, das zweite jedoch durch <ol> (nummerierte Liste).
Durch "mehrmaliges Parsen" käme man aber zu folgendem Ergebnis:
HTML:
<ul>
<li>Blabla</li>
<li>Foobar</li>
<li>Lalala
<ol>
<li>Lalala 1</li>
<li>Lalala 2</li>
</ul></li>
<li>Dummy</li>
</ol>
Die Listen sind also nicht mehr ordnungsgemäß verschachtelt, ich glaube kaum dass das in irgendeinem Browser noch ansehbar aussähe (von validem HTML ganz zu schweigen).

Gruß,
Xgame
 
So mal den Thread wieder ausgrab:

Kann mir einer von euch sagen warum das nicht funktioniert?
ich habe einen String [ul=circle] und diesen RegEx
PHP:
'~(?<!\\\)\[ul(?<==)=(\w+)\]((?:[^[]|\[(?!/?ul])|(?R))+)\[/ul\]~i'
Ich will das der RegEx nur True ist wenn wirklich nur ein wort hinter = steht. Deswegen dachte ich mir das geht doch mit einer positiven Lookbehind-Assertion. Aber das funktioniert so nicht warum auch immer und jegliches Tut brachte mich nicht weiter.
 
Zuletzt bearbeitet:
So dann grab ich den mal wieder aus :roll: ich versuche mich gerade an einer suma mit nem Bot. Dafür habe ich mir nen regex geschrieben der mit ale links aus dem html holt. Jetzt will ich aber link mit einer # einem / nicht haben da diese wieder auf die Index der Seite oder irgendwelche Anker linken.

PHP:
      preg_match_all('/<a\s?href="?([^"#\/{1,1}]*?[^"\s])\s?(?:title="?([^"]*?[^"]))?(?:.+)?>([^>]*?[^<])<\/a>/iU', $this->_string['body'], $link, PREG_SET_ORDER);
...a\s?href="?([^"#\/{1,1}]*?[^"\....
ich habe es mal rot markiert was nicht funktioniert. Aktuelle holt er die links die einen / drin haben schneidet aber den rest ab. Ich will dem regex aber sagen keine link die NUR einen / enthalten.

Btw: ist der so ok kann man was verbessern oder gibts was zu meckern?
 
also {1,1} gibt's so nicht.. wenn du exakt eines haben willst, dann tut's {1} oder (afaik) auch einfach weglassen ;)
 
Naja also 1,1 müsste es schon geben weil das exact eins heist also im grunde wie ?. Aber mein Problem wenn ich {1} schreibe heist das min 1 aber unendlich viele, wenn ich das noch richtig in Erinnerung habe und wenn ich es komplett weglasse also nur \/ schreibe dann sollte ich normalerweise alles bis zum ersten / erhalten, also auch nicht das was ich will. Der soll den link nur ausschließen wenn wirklich nur / geschrieben ist ohne zeichen davor oder danach.

*edit

gerade gelöst
PHP:
preg_match_all('/<a\s?href="?([^"#][a-z0-9:.-_\/]*?[^"#\s])\s?(?:title="?([^"]*?[^"]))?(?:.+)?>([^>]*?[^<])<\/a>/iU', $this->_string['body'], $link, PREG_SET_ORDER);

Jetzt die Frage ob der so in Ordnung ist oder nicht. Leider ist ja bei ner Suma das Prob das Html auch invalid sein kann, der Bot aber die Links trotzdem erkennen muss, das macht es halt schwer.
 
Zuletzt bearbeitet:
Naja also 1,1 müsste es schon geben weil das exact eins heist also im grunde wie ?.
Nope. x{1,1} macht keinen Sinn, da das bedeutet, dass Du x mindestens und höchstens 1 Mal haben willst. Das ist demzufolge äquivalent zu einfach nur x. Das Fragezeichen hingegen bedeutet 1 Mal oder kein Mal und macht die Angabe, nach der das Fragezeichen steht, demzufolge optional.