Reguläre Ausdrücke

Alles, was PHP betrifft, kann hier besprochen werden.

Reguläre Ausdrücke

Postby startist » 27. August 2008 10:37

Hallo,

ich muss mich mal wieder an das Forum wenden, da ich so meine Schwierigkeiten mit regulären Ausdrücken habe. Ich nutze Sie zwar öfter, aber wenn es einige Unbekannte gibt, verstricke ich mich in Wirrwarr. So wie jetzt.

Ich möchte ein Eingabefeld überprüfen, welches nur die Werte -99,00 bis 99,00 haben darf. Dazu nutze ich die Funktion eregi().

Aber schon der Anfang funktioniert nicht:
Code: Select all
if (!eregi('([-]{0,1})+([0-9]{1,2}),([0-9]{0,2}))', $newDL) { $error = $erg[3]; }

Hier habe ich versucht, zu überprüfen, ob am Anfang ein - vorkommt (soll ja erlaubt sein, ist aber kein Muss). Danach kontrolliere ich die Zahlen und das Komma. Ohne die vorhergehende Überprüfung nach dem - funktioniert das auch.

Aber eigentlich kommts noch dicker, da natürlich auch Werte ohne Komma akzeptiert werden sollen, dann fallen auch die Zahlen nach dem Komma flach.

Also ich blick's nicht, obwohl ich eine Seite im Netz gefunden habe, die reguläre Ausdrücke eigentlich gut erklärt. Dennoch komme ich nicht weiter. Kann mir jemand sagen, wie man das richtig angeht?

Danke, startist
User avatar
startist
 
Posts: 55
Joined: 24. June 2008 14:10
Location: Dresden

Postby Wiedmann » 27. August 2008 10:55

Ich möchte ein Eingabefeld überprüfen, welches nur die Werte -99,00 bis 99,00

Ale eigentlich testet das von -99,99 bis 99,99.

in der Theorie:
Code: Select all
if (preg_match('/-?\d{1,2}(?:,\d{1,2})?/', $subject)) {
   # Successful match
} else {
   # Match attempt failed
}



BTW:
Man benutzt heutzutage natürlich preg und nicht ereg.
Wiedmann
AF Moderator
 
Posts: 17102
Joined: 01. February 2004 12:38
Location: Stuttgart / Germany

Postby startist » 27. August 2008 11:08

Vielen Dank, so geht es, ich werde es aufmerksam studieren, um auch den Zusammenhang zu erkennen.
Man benutzt heutzutage natürlich preg und nicht ereg.

Das wusste ich nicht, werd's mir merken.
User avatar
startist
 
Posts: 55
Joined: 24. June 2008 14:10
Location: Dresden

Postby Nobbie » 27. August 2008 11:11

>Hier habe ich versucht, zu überprüfen, ob am Anfang ein - vorkommt (soll ja erlaubt sein, ist aber kein Muss)

Das ist schon der erste Fehler - in Deiner Expression ist das Minuszeichen Pflicht. Und (leider) die ganze Expression ist ziemlicher Müll. Du hast total umständlich gedacht.

Gehen wir der Reihe nach:

Am Anfang steht ein Minuszeichen, aber nur optional und auch nur eines. Das Pattern, was "Anfang" einer Zeichenkette bedeutet, ist der Zirkonflex '^'. Danach kann ein oder kein Minuszeichen kommen - das Zeichen, welches das davorliegende 0 oder 1 Mal mal qualifiziert, ist das Fragezeichen '?'. Damit haben wir den Anfang:

Code: Select all
^-?


Du hast dort die Klassendefinition [-] stehen, die völlig sinnlos ist, weil dort normalerweise Mengen von Zeichen stehen. Ich kann Dir an anderer Stelle mal erklären, was die eckigen heißen. Außerdem hast Du auch tonnenweise zuviele Backreferenzen definiert, das sind die runden Klammern auf und zu - die brauchst Du auch nicht.

Aber wir machen weiter. Jetzt ist die Frage, muss die Eingabe exakt zweistellig plus Komma plus zweistellig dahinter sein, oder darf vor dem Komma auch nur eine Stelle stehen? Ich mache beide Fälle. Erst der Fall "genau zweistellig":

Code: Select all
^-?[0-9][0-9],[0-9][0-9]$


Das Dollarzeichen bedeutet "Ende" des Eingabestrings. Achtung: ggf. mußt Du den Eingabestring mit trim() kürzen, denn sonst werden nachfolgende Leerstellen zu Fehlern in der Erkennung führen.

Die Klasse [0-9] kann man sogar noch abkürzen, denn ein digitales Zeichen kann man auch direkt mit \d suchen:

Code: Select all
^-?\d\d\.\d\d$


Und nun noch der Fall, dass vor dem Komma eine oder zwei Stellen stehen:

Code: Select all
^-?\d+,\d\d$


Das Pluszeichen '+' bedeutet, das vorhergehende Zeichen mindestens einmal und optional noch einmal (also insgesamt zweimal). Das gleiche erlauben wir nun hinter dem Komma auch noch, und dann sieht es so aus:

Code: Select all
^-?\d+,\d+$


Und das war es. Die Start- und Endezeichen sind wichtig, weil sonst auch "eingebettete" Zeichenketten als erlaubt durchkämen, beispielsweise der Satz "das kostet 23,45 Euro" würde als ganzes akzeptiert werden.

Dann solltest du nicht die ereg-Funktionen verwenden, das sind erweiterte reguläre Ausdrücke, die etwas rechenintensiver sind aber gar nicht benötigt werden, die eregi()-Funktion ignoriert auch noch Gross-Kleinschreibung, das brauchst Du ebenfalls nicht. Nimm die einfach preg_match-Funktion, da muss man im Unterschied zu ereg-Funktion das Pattern noch "einschließen" in Start- und Endezeichen, üblicherweise der Slash '/' (man kann aber auch andere Zeichen nehmen, das bietet sich dann an, wenn der Slash im Suchpattern selbst gebraucht wird).

So sieht es zum Schluss aus:

Code: Select all
if (!preg_match('/^-?\d+,\d+$/', $newDL)) ...


P.S.: Ich sehe gerade noch den Vorschlag von "Wiedmann", die erlaubt auch Eingaben von Werten ohne Komma. Allerdings fehlen da die Start-Ende-Begrenzer. Das kann man natürlich zusammenfügen (und vereinfachen - der optionale Operator ?: ist nicht notwendig, da die Zahl davor sowieso verpflichtend ist):

Code: Select all
if (!preg_match('/^-?\d+(,\d+)?$/', $newDL)) ...


P.P.S.: Oups! Ich bin doof - der +-Operator frißt zuviel, man muss doch entweder \d\d? oder \d{1,2} nehmen:

Code: Select all
if (!preg_match('/^-?\d{1,2}(,\d{1,2})?$/', $newDL)) ...
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Postby Xardas der Dunkle » 27. August 2008 14:33

Mir stellt sich die Frage, wieso überhaupt ein RegEx!?
RegExp sind langsam und sollten nur benutzt werden wenn man sie auch wirklich brauch, da du ja nur eine Zahl einließt währe:
Code: Select all
<?php
$input = floatval(str_replace(',', '.', $newDL));
if($newDL != $input || $input > 99.00 || $input < -99.00) {
    // Error
} else {
    // ...
}

imo sinnvoller.
User avatar
Xardas der Dunkle
 
Posts: 482
Joined: 09. March 2008 19:40
Location: /var/www

Postby Nobbie » 27. August 2008 15:08

Xardas der Dunkle wrote:Mir stellt sich die Frage, wieso überhaupt ein RegEx!?


Wie willst Du denn mit floatval() sicherstellen, dass nur 2 Stellen hinter dem Komma angegeben werden dürfen (also 12,234 ist NICHT erlaubt)?

Außerdem ist es ein Gerücht, dass RegExp zu langsam sind. Und es stellt sich die Frage, ob floatval() überhaupt schneller arbeitet.

Zudem funktioniert Dein Script vorne und hinten nicht. Für jede Kommazahl größer als 99 (oder kleiner als -99) wird Fehler ausgegeben.
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Postby Xardas der Dunkle » 27. August 2008 15:20

Die länge abzufangen ist ja das kleinere Problem.

Zudem funktioniert Dein Script vorne und hinten nicht. Für jede Kommazahl größer als 99 (oder kleiner als -99) wird Fehler ausgegeben.

welches nur die Werte -99,00 bis 99,00 haben darf.
User avatar
Xardas der Dunkle
 
Posts: 482
Joined: 09. March 2008 19:40
Location: /var/www

Postby Nobbie » 27. August 2008 15:45

Xardas der Dunkle wrote:Die länge abzufangen ist ja das kleinere Problem.


Die Länge allein reicht nicht. Denn 1,234 ist nur 5-stellig aber dennoch nicht erlaubt.

Dann wird es langsam komplizierter.
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04

Postby Wiedmann » 27. August 2008 17:56

der optionale Operator ?: ist nicht notwendig, da die Zahl davor sowieso verpflichtend ist

"?:" hilft hier Speicher sparen, weil die Gruppe nicht für später zwischengespeichert wird wie normal bei "()" (capture group) .
Wiedmann
AF Moderator
 
Posts: 17102
Joined: 01. February 2004 12:38
Location: Stuttgart / Germany

Postby Nobbie » 27. August 2008 22:21

Wiedmann wrote:"?:" hilft hier Speicher sparen, weil die Gruppe nicht für später zwischengespeichert wird wie normal bei "()" (capture group) .


In Zeiten von 2GB RAM?
Nobbie
 
Posts: 13176
Joined: 09. March 2008 13:04


Return to PHP

Who is online

Users browsing this forum: No registered users and 16 guests