| Hier finden sie einige bunt gemischte Beispiele aus der IT-Praxis - Sorgfältig getestet, jedoch ohne Anspruch auf Unfehlbarkeit. test |
Fast alle Beispiele sind in Perl-Syntax
angegeben, weil Perl ideal zur Verarbeitung von Texten geeignet ist. Alle verwendeten Regulären Ausdrücke sind mit dieser Farbe markiert. |
Regular Expressions
|
Einführung in das Thema 'Regular Expressions' (RE) |
| RE - Syntax | Grammatik der Regular Expressions (mit Beispielen) |
| RE in Programmen | Anwendung von RE in Programmiersprachen und Programmen |
Live RE Online
|
Live mit RE experimentieren |
| Beispiele: | |
| Datum & Zeit | ISO-Datum |
| Datei-Pfade | Volume, Pfad, Dateiname, Erweiterung, Anker, URI-Argumente |
| 'Fließtext' | Allgemeiner Text |
| Validierung einer Mail-Adresse test@provider.com | |
| IP | Verarbeitung von IP-Adressen und Ports |
| XML | XML und andere Auszeichnungs-Sprachen |
| Suche | Suche nach 'benachbarten' Stichworten |
RegExp mit Datum & Zeit |
|
| In diesem Kapitel wird häufig das RegExp-Symbol \d für die dezimalen Ziffern [0-9] verwendet. | Die RegExp-Funktionen mancher Programmiersprachen unterstützen nur wenige RegExp-Symbole. Verwenden sie in diesem Fall [0-9] für dezimale Ziffern. |
ISO-8601● Datum- und Zeit-Angaben nach → ISO-8601 sind ideal für die IT-Verarbeitung geeignet.Das aktuelle ISO-Datum ihres PC ist 2000-01-01 00:00:00 Das ISO-Datum ist streng nach Wichtigkeit der einzelnen Teile aufgebaut und kann nach jedem Teil abgebrochen werden, wenn die restliche Information nicht verfügbar oder uninteressanrt ist. ● Das Beispiel rechts zeigt zunächst die Aufspaltung aller vorhandenen Teile mit Funktion split() (PHP: preg_split() ) Jeder gefundene Datum-Zeit-Teil wird zeilenweise ausgegeben. ● Danach wird gezeigt, wien man die beiden Teile 'Datum' und 'Zeit' isoliert. Die RegExp funktionieren auch dann, wenn nur einer der beiden Teile vorliegt, oder wenn zusätzlich Sekunden-Bruchteile angegeben werden. ● Zuletzt wird am Beispiel von Monaten und Minuten demonstriert, wie man gezielt bestimmte Teile isolieren kann. Beachten sie die Möglichkeit, Ziffern wahlweise mit \d oder mit [0-9] anzugeben. ● Es gibt in Sonderfällen auch ISO-Varianten ohne Trennzeichen: 20000101000000 Das Beispiel rechts zeigt die 'Herstellung' aus einem Standard ISO-String. ● Details zum Standard ISO-8601. |
$t = '2000-01-01 00:00:00';
my(@iso) = split(/[-: ]/,$t); foreach $dt (@iso) {print "$dt\n";} if ($t=~m/([\d-]{4,10})/) { print "Datum = <$1>\n";
}if ($t=~m/(\d\d\:.*)/) { print "Zeit = <$1>\n";
}if ($t=~m/\d\d\d\d-(\d\d)/) { print "Monat = <$1>\n";
}if ($t=~m/\d\d:(\d\d)/) { print "Minute = <$1>\n";
}// Variante ohne Trennzeichen $t =~ s/[-: ]//g; |
DIN-5008Ist veraltet und durch → ISO-8601 ersetzt, wird jedoch noch häufig angetroffen. Hier werden RegExp gezeigt, die mit der numerischen Variante arbeiten, z.B.1.1.2000 00:00:00
Leider sind auch Varianten mit Text-Angabe möglich, wie
z.B. 1.Jänner 2000, diese sprach-spezifischen
Angaben sind jedoch in einem mehrsprachigen Gebiet wie der EU nicht eindeutig
und sollten daher nicht mehr verwendet werden.Sonderzeichen (hier z.B. ä) verschiedener Sprachen komplizieren das Problem weiter. ● Das Beispiel zeigt zuerst die Aufspaltung und Ausgabe aller Bestandteile. Vorsicht bei Sekunden-Bruchteilen, da in der EU sowohl Dezimal-Punkt als auch Dezimal-Komma in Gebrauch sind. ● Danach werden die gleichen Bestandteile isoliert wie oben im Standard ISO Datum gezeigt. ● Führende Wochentage wie z.B. Fr, 13.4.2001 werden am besten ignoriert, und das Datum mit dem internen → Kalender der jeweiligen Programmiersprache berechnet. |
$t = '1.1.2000 00:00:00';
my(@dt)=split(/[\.: ]/,$t); foreach $dtn (@dt) {print "$dtn\n";} if ($t=~m/(\d{1,2}\.\d{1,2}\.\d{2,4})/) { print "Datum = <$1>\n";
}if ($t=~m/(\d\d\:.*)/) { print "Zeit = <$1>\n";
}if ($t=~m/\d{1,2}\.(\d{1,2})\./) { print "Monat = <$1>\n";
}if ($t=~m/\d\d:(\d\d)/) { print "Minute = <$1>\n";
}
|
RFC-822Diese eher chaotische Datum-Formatierung ist dem US-Einflussgebiet vorbehalten:
Sat, 1 Jan 2000 00:00:00 +010
●
Es gibt von diesem und anderen US-Formaten so viele Varianten, dass es
unmöglich ist, allgemein verwendbare RegExp zu entwickeln. Nur wenn die
Format-Variante genau festgelegt ist, lässt sich ein derartiger String
sauber decodieren.● Das Jahr kann 2stellig oder 4stellig sein, es kann zusammen mit Tag und Monat oder getrennt davon nach der Zeit (!) codiert sein. |
● Die Reihenfolge von Tag und Monat ist meist (wie im US-Sprachgebrauch) DD-MM, kann jedoch auch umgekehrt sein. Weil das natürlich zu Verwechslungen führt, wird der Monat meist nicht als Zahl, sondern als String (Text) angegeben. Das können Strings fixer Länge (3 Zeichen) oder variabler Länge January..December sein. ● Als Trennzeichen zwischen den Datum-Teilen sind Leerzeichen oder Minus-Zeichen möglich. ● Die Zeit sollte zwar in allen Varianten einheitlich im Format HH:MM:SS codiert sein, man trifft jedoch auch auf Varianten im US-12 Stunden-Format mit den Zusätzen AM bzw. PM . In diesem Fall muss man die 4 Bereiche 00:00 bis 00:59, 01:00 bis 11:59, 12:00 bis 12:59 und 13:00 bis 23:59 jeweils unterschiedlich decodieren ! |
Umwandlung in ZahlenMit Regulären Ausdrücken kann man nur Strings (Text) isolieren. Normalerweise werden jedoch Zahlen zur weiteren Verarbeitung benötigt.Die Umwandlung in Zahlen erfolgt je nach Programmiersprache unterschiedlich: In → Perl und → PHP genügt es, die Zahl 0 zu addieren. Undefinierte TeileSie müssen selbst entscheiden, was mit eventuell nicht gefundenen Datum und Zeit-Teilen geschehen soll. Meist wird Tag..Monat = 1 gesetzt, sowie Stunde..Sekunde = 0. Wenn das Jahr fehlt, dann wird meist das aktuelle Jahr (Risiko !) oder 0 eingesetzt. |
ValidierungNach Umwandlung der isolierten Texte in Zahlen muss deren Werte-Bereich überprüft werden:Monate 1..12, Tage 1..31 Stunden 0..23, Minuten 0..59, Sekunden 0..59 ● Manche Programmiersprachen zählen die Monate im Bereich 0..11 ● Jahre sind nur mit 4stelliger Angabe eindeutig ! (Abgesehen von historischen Jahren<1000). 2stellige Jahreszahlen<100 müssen in heiklen Anwendungen zurückgewiesen oder manuell überprüft werden. In harmlosen Fällen wird eine willkürliche Grenze gezogen: Zu Jahreszahlen<30 wird z.B. 2000 addiert, zu Jahreszahlen>=30 die Zahl 1900. Das ergibt Fahler, wenn (2stellige) Jahreszahlen<1930 vorkommen können ! |
RegExp mit Datei-Pfaden |
|
|
Datei-Pfade kann man in Perl immer mit dem
Separator-Zeichen / verwenden,
auch in Windows-Systemen ! Dort kann man zwar auch \
verwenden, man muss jedoch die Maskierung beachten. ● Gängige Programmiersprachen bieten meist bequeme Funktionen zur Verarbeitung von Datei-Pfaden. Die hier gezeigten RegExp-Beispiele werden daher nur in Sonderfällen eingesetzt. |
$t = '/home/daten/test.txt';
$t = 'c:/daten/test.txt'; $t = "c:\\daten\\test.dat"; $t = 'http://www.prov.com/test.dat'; |
|
Beispiel für einen komplexen Pfad-Text:
$t = 'http://www.provider.com/daten/test.php#anker?a=xyz&b=123';
|
|
| Funktion split() (alle gängigen Programmiersprachen, PHP: preg_split() ) trennt einen Pfad mit der angegebenen RegExp und gibt die Einzelteile $x als Array @pa zurück. Sie werden im Beispiel zeilenweise einzeln ausgegeben. Die Funktion unterdrückt den Trenn-Text (meist nur 1 Trenn-Zeichen), d.h. die /-Zeichen sind in den Array-Elementen nicht enthalten. |
@pa = split(/\//,$t);
foreach $x(@pa) { print "$x\n";
}
|
|
Nach Aufspaltung des Pfad-Textes in ein Array (hier
@pa) kann man die einzelnen Elemente aufarbeiten: ● Eine Web-Adresse (URL) beginnt mit http:// (bzw. ftp:// usw. für andere Dienste). In diesem Fall findet man den Provider prov im 3. Array-Element mit dem Index 2. ● Windows-Volumes vol enthalten im ersten Array-Element nur einen einzelnen → ASCII-Buchstaben, gefolgt von einem Doppelpunkt. ● Der rohe Dateiname $f befindet sich im letzten Array-Element mit dem Index -1 oder $#pa. Er wird zunächst von allfällig vorhandenen Ankern oder GET-Texten (s.u.) isoliert und nach dem letzten enthaltenen Punkt \. in den Namen nam und die Datei-Erweiterung ext aufgespalten. ● Ein Anker ist eine Sub-Adresse auf der Webseite, sein Name ist durch ein #-Zeichen vom Dateinamen getrennt. Falls vorhanden, wird ank ausgegeben. |
# Web-Pfad
if($pa[0]=~m/^http:/) {
print "web prov=".$pa[2]."\n";
}
# Win-Volume
if($pa[0]=~m/^([A-Za-z]):$/) {
print "vol $1\n";
}
# Filename
$f=$pa[-1];if($f=~m/([^#?]*)/) {
print "file = $1\n";
}
$1=~m/(.+)\.([^\.]*)$/; print "nam=$1, ext=$2\n" # Anker
if($f=~m/#([^?]*)/) {print "ank=$1\n";}
|
Argumente:Ein besonderer Fall ist die Übergabe von Daten-Argumenten, in der URI-Adresszeile eines Browsers.♦ Details in den Kapiteln → CGI-Programme und → URI-Formatierung. ● Wenn mit der GET-Methode (→ CGI) Daten an das Ziel-Programm übergeben werden, dann sind diese 'URI-codiert' und vom Dateinamen durch ein ?-Zeichen getrennt. Das findet man z.B. in der Browser-Adresszeile nach jeder Suche auf einer Web-Suchmaschine. ● Ein solcher Text kann mehrere Argumente enthalten, die voneinander durch &-Zeichen getrennt sind. Die Aufspaltung in das Array @u erfolgt wieder mit Funktion split(). ● Jedes einzelne Argument $x ist in der Form name=wert enthalten, diese beiden Teile können daher durch weitere Aufspaltung nach =-Zeichen isoliert werden. ● Das Beispiel funktioniert nur für einfache Argumente. Wenn im → URI-Text Sonderzeichen codiert sind, müssen sie diese danach decodieren. |
# URI
if($f=~m/\?([^#]*)/) {
print "get = $1\n";
}
@u = split(/&/,$1); foreach $x(@u) {
print " $x -> ";
}
@nv = split(/=/,$x); $n = $nv[0]; $v = $nv[1]; print "n=$n, v=$v\n"; |
Javascript-Argumente:Alle mit Webservern verwendeten Programmiersprachen (→ Perl, → PHP, ..) bieten Standard-Funktionen für die bequemere Isolierung verschiedener Bestandteile von Pfad-Strings auch ohne RegExp.Eine Ausnahme bildet offenbar Javascript. Es ist wenig bekannt, dass man in der URI-Befehlszeile auch an Javascript und damit an 'gewöhnliche' Webseiten Daten übergeben kann. ● Das Beispiel rechts zeigt, wie man das auch ohne spezielle Funktionen mit RegExp machen kann. In der for-Schleife wird für jedes Argument der Name n und sein Wert v isoliert. Die Daten werden anschließend verarbeitet, was hier nur angedeutet wird. ♦ Details zum Thema Javascript-Argumente. |
Decodierung von GET-Argumenten mit Javascript:
h = location.href;
h.match(/\?(.*)/); get = RegExp.$1; args = get.split("&"); for(i=0;i<args.length;i++) {
nv = args[i].split("=");
}
n = nv[0]; v = nv[1]; // Verarbeitung, z.B.
alert("GET("+n+")="+v);
|
Selektive Pfad-SpaltungIn der Praxis ist man meist an ganz bestimmten Teilen eines typischen Pfades interessiert.Das Beispiel spaltet einen Pfad zuerst nach dem / Trennzeichen, isoliert das letzte Element (filename=reta[1]) und setzt den restlichen Pfad wieder zusammen (dirname=reta[0]). Danach wird der Dateiname nach . Punkt gespalten, das letzte Element (xtn=reta[3]) isoliert und der Rest zum Namen (name=reta[2]) zusammengesetzt. Alle 4 Elemente werden in einem → Array an das aufrufende Programm zurückgegeben. |
Selektive Spaltung eines Dateisystem-Pfades mit Perl:
sub split_path {
Anwendung:
# Returns (dirname,filename,name,xtn)
my ($path) = @_;
}
my @reta = ('','','',''); my @pa = split(/\//,$path); $reta[1] = splice(@pa,$#pa,1); $reta[0] = join('/',@pa); my @na = split(/\./,$reta[1]); $reta[3] = splice(@na,$#na,1); $reta[2] = join('/',@na); return @reta;
$path = 'C:/abc/xyz/test.dat';
@pa = split_path($path); foreach $v(@pa) {print "$v \n";} |
RegExp mit 'Fließtext' |
|
Zeilen-Umbruch:● An die Variable $t1 wird (nur dann) ein LF (neue Zeile \n) angefügt, wenn es sich nicht schon am Ende (Position $) befindet.● Aus der Variablen $t2 werden alle vorhandenen CR oder LF-Zeichen unabhängig von ihrer Position entfernt (Substitute mit einer 'leeren Menge'). |
my($t1,$t2)='test';
// LF bei Bedarf anfuegen
if(!($t1=~m/\n$/)) {
$t1.="\n";
}
// CR oder LF entfernen
$t2=~s/[\n\r]//g;
|
|
Der Zeilen-Umbruch muss insbesondere bei der zeilenweisen Verarbeitung von
Text berücksichtigt werden: |
Längere Text-Dateien können jedoch nur zeilenweise verarbeitet werden. Wenn sich wichtige Strukturen evtl. über mehrere Zeilen erstrecken können, dann müssen sie in ihren Programmen 'angefangene' Stukturen in einer Variablen evtl. über mehrere Zeilen hinweg sammeln, und erst dann verarbeiten, wenn diese Strukturen beendet sind (z.B. ↓ XML-Daten). |
TrimDie Entfernung überflüssiger Leerzeichen erfolgt mit RegExp besonders elegant. Die 3 Beispiele rechts entfernen führende Leerzeichen ($ta), folgende Leerzeichen ($tz, 2 Versionen) oder beide ($taz).Wenn eine Programmiersprache kein \s kennt, ersetzen sie es durch [\t\r\n ] Im Beispiel werden in $tm alle Mehrfach-Leerzeichen durch einfache Leerzeichen ersetzt. Der Ausführungs-Teil der while-Schleife bleibt leer, weil die ganze Arbeit bereits in der Bedingung erledigt wird. |
$t = ' xyz ';
Entfernen von Mehrfach-Leerzeichen:
$ta =~ s/^\s+//; $tz =~ s/\s+$//; $t =~ m/(.*?)\s+$/; $tz = $1; $taz =~ s/^\s+|\s+$//g;
$tm = 'a b c';
Javascript-Trim-Funktion:
while($tm=~s/\s\s/ /) {}
function trim(t) {
t=t.replace(/^\s+/,'');
}
t=t.replace(/\s+$/,''); while(t.match(/ /)) {t=t.replace(/ /," "); } return t; |
Langer Text:● Variable $t kann einen langen Text enthalten, der in handliche Portionen zerlegt und ausgegeben werden soll, hier z.B. zu je max. 50 Zeichen. Wenn am Ende noch Text übrig ist, wird er ebenfalls ausgegeben. Das erste Beispiel zeigt eine 'harte' Trennung ohne Rücksicht auf Trennzeichen.● Das zweite Beispiel zeigt eine Trennung an Wort-Grenzen (mit Leerzeichen \s). Zuerst wird ein Text-Stück maximaler Länge (hier 50 Zeichen) isoliert. Darin wird das letzte vorkommende Trennzeichen gesucht, der Text davor ausgegeben, der Text danach vor den Rest des Strings $t gesetzt. ● An Stelle des Trennzeichens \s können beliebige andere Zeichen verwendet werden - Wenn sie z.B. [ ,;] einsetzen, dann wird nach Leerzeichen, Beistrich oder Strichpunkt getrennt, je nachdem, welches dieser Zeichen zuerst gefunden wird. Wenn sie das Trennzeichen selbst unterdrücken wollen, dann entfernen sie es aus der ersten () und setzen es zwischen die beiden ()(). |
Harte Trennung:
while($t=~s/(.{50})//) {
Trennung an Wortgrenzen
print "$1\n";
}if($t) {print "$t\n";}
while($t=~s/(.{50})//) {
$1=~m/(.*\s)([^\s]*)/;
}print "$1\n"; $t=$2.$t; if($t) {print "$t\n";} |
Non-ASCII und Unicode● Die Anwendung von RegExp auf 1-Byte Zeichen ist nur im → ASCII-Bereich U+00..U+7F absolut sicher (von der richtigen Verwendung abgesehen).
Die Anwendung von RegExp auf 1-Byte Zeichen U>007F ist daher riskant
und möglichst zu vermeiden !
Die Beispiele rechts zeigen, dass RegExp berücksichtigen müssten,
ob ein Text $t auf DOS (an der Konsole oder durch
ein Konsolen-Programm) oder Win, MacOS, ... erstellt wurde.
Die deutschen Sonderzeichen äöü werden
in DOS, Windows und MacOS sogar bei gleicher Sprache anders codiert. Auf einem
osteuropäischen, russischen oder US-PC würden damit ganz andere
Zeichen erfasst.● Zeichen U>00FF sind mit 1 Byte nicht mehr darstellbar, werden daher meistens → UTF-8 codiert und sind in dieser Form weltweit eindeutig. Auf UTF-8 Strings beliebiger Unicode-Zeichen U+0000..U+FFFF können daher RegExp ohne Risiko angewendet werden. Je nach Programmiersprache werden für → Unicode-Strings z.T. eigene Funktionen verwendet. |
$t = "wäre überdies größer";
if($t=~m/(\x{0084})/) {print "DOS ae <$1>\n";} if($t=~m/(\x{00E4})/) {print "Win ae <$1>\n";} if($t=~m/(\x{0094})/) {print "DOS oe <$1>\n";} if($t=~m/(\x{00F6})/) {print "Win oe <$1>\n";} if($t=~m/(\x{0081})/) {print "DOS ue <$1>\n";} if($t=~m/(\x{00FC})/) {print "Win ue <$1>\n";} |
CleanDie rechts vorgestellte Funktion clean() entfernt aus einem Text alle eventuell störenden Zeichen, hier z.B.• Null-Byte (von Hackern gerne verwendet) PHP muss das Null-Byte mit \x{0} codieren. • Steuerzeichen (Tab, CR, LF...) 00-1F • BackSlash 5C • Tilde und Non-ASCII (ÄÖÜäöüß) 7E-FF • Der übrig bleibende Text wird auf die eingestellte maximale Länge (hier 20 Zeichen) gekürzt und zurückgegeben. Das Javascript-Beispiel (ohne Begrenzung der Länge) verwendet die ↑ oben vorgestellte Funktion trim() |
sub clean {
Anwendung in Perl:
my ($txt)=@_;
}
$txt=~s/[\x00-\x1F\x5C\x7E-\xFF]//g; if($txt=~m/(.{1,20}).+/) {$txt=$1;} return $txt; $clean_string = clean($text);
Einfache Cleaner-Funktion in Javascript:
function clean(t) {
t=t.replace(/[\x00-\x1F\x5C\x80-\xFF]/g,'');
}
t=trim(t); |
|
Eine 'Cleaner'-Zeile in PHP:
$txt = preg_replace("/[\x{0}-\x{1F}\x{5C}\x{7E}-\x{FF}]/",'',$txt);
|
|
Entfernung von XML oder HTML < >-ElementenManchmal ist es notwendig, aus einem Text alle Auszeichnungs-Elemente zu entfernen und nur die 'reinen' Daten zu isolieren. Danach kann man verbleibende Mehrfach-Leerzeichen durch einfache ersetzen. |
$txt = 'abc <xyz> 123 </xyz> def <rst/>'
$txt=~s/<[^>]+>//g; while($tm=~s/\s\s/ /) {} |
Validierung von Mail-Adressen mit RegExp |
|
| Mail-Adressen werden relativ oft in HTML-Formulare eingetragen und anschließend an eine Empfangs-Webseite abgesendet. Die Empfangs-Seite ist normalerweise eine dynamische Webseite, d.h. ein Script-Programm (PHP, Perl, ...). Es ist sinnvoll, eine eingegebene Mail-Adresse vor der weiteren Verarbeitung auf ihre Zulässigkeit zu prüfen (=Validierung). |
Der Webserver sollte so wenig wie möglich belastet werden. Daher erfolgt
die Validierung immer zuerst auf der Absender-Webseite (d.h. mit
→
Javascript) ! Bei Eingabe einer offensichtlich fehlerhaften Adresse erfolgt eine Fehlermeldung und eine erneute Eingabe - Ohne Belastung des Webservers ! Nur geprüfte und für korrekt befundene Mail-Adressen werden an die Empfangs-Webseite am Webserver weitergeleitet. |
|
Typisches HTML-Formular zur Eingabe einer Mail-Adresse: Das <button>-Element startet beim Anklicken die Javascript-function absenden |
<form name="form1" method="get"
action="empfang.php">
Ihre Mail-Adresse:<br> <input type="text" name="madr" size="30"> <button onclick="absenden()"> Absenden </button> </form> |
|
Im <head> der gleichen HTML-Webseite ist die
Funktion absenden in einem
<script>-Element enthalten: Der in das Formular-Feld eingetragene Text wird mit Funktion validate() überprüft. Nur dann, wenn der Test positiv ausfällt, wird das Formular mit der Methode submit() abgesendet. In jedem anderen Fall erfolgt eine Fehlermeldung. |
function absenden() {
var madr = document.form1.madr.value;
}
if(validate(madr)) { document.form1.submit();
}else { alert("Fehlermeldung");
}
|
|
Die Javascript-Funktion validate() führt mit dem
übergebenen Text t verschiedene Tests aus. ● Variable r wird zurückgegeben. Sie wird false gesetzt, wenn einer der Tests negativ ausfällt. ● Der Text t wird am ersten Zeichen @ in 2 Teile t1 und t2 getrennt. ● Das erste Zeichen beider Teile muss ein → ASCII-Buchstabe sein. ● In jedem Teil sind nur bestimmte Zeichen (Ziffern, → ASCII-Buchstaben, - Minus, _ Underline und . Punkt zulässig. ● Die Länge der beiden Teile muss mindestens 2 bzw. 5 Zeichen betragen. ● Der zweite Teil muss mindestens einen Punkt enthalten, davor und danach mindestens 2 andere Zeichen. |
function validate(t) {
var r = 1;
}
// Trennung am @
if(t.match(/([^@]*)@(.*)/)) {
var t1=RegExp.$1; var t2=RegExp.$2;
}else {r=0;} if(r) { // Erstes Zeichen
if(!t1.match(/^[A-Za-z]/) || !t2.match(/^[A-Za-z]/)) {r=0;}
// Zulaessige Zeichen
if(t1.match(/[^0-9A-Za-z-_\.]/) || t2.match(/[^0-9A-Za-z-_\.]/)) {r=0;}
// Anzahl Zeichen
if(t1.length<2) {r=0;}
// Punkt
if(!t2.match(/[^\.]{2,20}\.[^\.]{2,30}/)) {r=0;}
return r; |
RegExp IP-Adressen |
|
Test und IsolationDas → Internet Protocol IPv4 verwendet 32-Bit Adressen.Die Darstellung erfolgt meistens in Form von Strings (Text) aus 4 Dezimalzahlen (jeweils 0..255) mit . Punkten als Trennzeichen. |
Verzweigung, wenn eine IPv4-Adresse in einem String enthalten ist,
und Isolation dieses Strings:
$s = 'abc 192.168.1.23 xyz';
if($s=~m/(\d+\.\d+\.\d+\.\d+)/) { print "ip = $1\n";
}
|
PortIn dieser Variante wird optional ein nachgestellter → Port berücksichtigt, falls angegeben. |
Isolation von IPv4-Adresse und Port
$s = 'abc 192.168.1.23:4567 xyz';
$s=~m/(\d+\.\d+\.\d+\.\d+:?\d*)/; |
ValidierungDieses Beispiel zeigt eine Möglichkeit zur Validierung von IPv4-Strings.Zunächst wird der String $ipv4 nach : gespalten, um einen allfällig enthaltenen Port zu isolieren. Das dabei erhaltene Array $pa darf nur die Länge 1 oder 2 haben, bei count>2 wird das Ergebnis der Validierung auf $ok=0 gesetzt. Wenn ein Port gefunden wurde, dann muss sein Zahlenwert 0..$n..65535 betragen. Danach wird der Adressen-String nach . gespalten. Wenn das Ergebnis-Array $ipa mehr oder weniger als 4 Elemente enthält, dann wird das Ergebnis auf $ok=0 gesetzt. Ansonsten wird jedes der 4 Elemente auf den zulässigen Bereich 0..$n..255 geprüft. Die Funktion gibt als Ergebnis 1 für zulässige oder 0 für fehlerhafte Strings zurück. |
Isolation von IPv4-Adresse und Port als PHP-Funktion
function ipv4_validate($ipv4) {
$ok = 1;
}$pa = preg_split("/:/",$s); // Port
if(count($pa)>2) {$ok=0;}elseif(count($pa)==2) {
$n = 0 + $pa[1];
}
if($n<0 || $n>65535) {$ok=0;} // Adresse
$ipa = preg_split("/\./",$pa[0]);if(count($ipa)==4) {
for($i=0;$i<4;$i++) {
}
$n = 0 + $ipa[$i];
}
if($n<0 || $n>255) {$ok=0;} else {$ok=0;} return $ok; |
MaskeDieses Beispiel zeigt, wie sich die 4 Teile getrennt isolieren lassen.Die Addition von 0 bewirkt eine implizite Umwandlung in eine Zahl. Meist ist es notwendig, zwischen IP-Adresse und Maske zu unterscheiden. Da alle praktisch verwendeten Masken mit 255 beginnen, wird das zur Unterscheidung verwendet. Lediglich die Broadcast-Adresse wird in diesem Fall falsch interpretiert. |
Getrennte Isolation der dezimalen Teil-Strings
$s=~m/(\d+)\.(\d+)\.(\d+)\.(\d+)/
$ipdig3 = 0 + $1; if($ipdig3==255) {print 'Maske';} else {print 'Adresse';} |
Basis-AdresseAus jeder IPv4-Adresse kann man die Basis-Adresse des lokalen Netzwerks (LAN) isolieren. Dabei wird die Maske 255.255.255.0 angenommen, was fast immer zutrifft.Im Beispiel wird aus einer beliebigen IP-Adresse (z.B. aus einer Umgebungs-Variablen oder fix vorgegeben) die Basis-Adresse ermittelt. An die Variable $lan (z.B. 192.168.0. endet mit Punkt !) kann man jede IP-EndZiffer 0..255 anhängen. Die Variable $lan0 (z.B. 192.168.0.0 ) enthält die erste LAN-Adresse = nominelle Basis-Adresse. |
my $srvadr=$ENV{'SERVER_ADDR'};
# $srvadr='192.168.0.1';
my $lan = $srvadr;$lan=~s/\d+$//; my $lan0 = $srvadr; $lan0=~s/\d+$/0/; |
Umwandlung String → Ganze ZahlFür die interne Verarbeitung sind ganze Zahlen besser geeignet als Strings.Das Beispiel zeigt eine PHP-Funktion ipv4_to_int(), die einen IP-String in eine ganze Zahl umwandelt. Der String wird zuerst nach : gespalten. Der erste Teil enthält die IP-Adresse, die nach . weiter gespalten wird. Danach werden die 4 Dezimalzahlen entsprechend ihrem Stellenwert in eine einzige ganze Zahl umgewandelt. Der (hier nicht verwendete) Port befindet sich in $pa[1] Die zurückgegebene ganze Zahl entspricht dem internen Format einer 32-Bit IPv4-Adresse. |
Umwandlung eines IPv4-Strings in eine ganze Zahl (Beispiel als PHP-Funktion):
function ipv4_to_int($ipv4) {
$pa = preg_split("/:/",$ipv4);
}
$ipa = preg_split("/\./",$pa[0]); $iip4 = 0; for($i=0;$i<count($ipa);$i++) { $iip4 = $iip4*256+$ipa[$i];
}return $iip4; |
Bit-ManipulationIn diesem Beispiel wird die Basis-Adresse des lokalen Netzwerks aus einer IP-Adresse $s ermittelt.Für die Berechnung wird der String in eine ganze Zahl umgewandelt. In dieser Form kann man alle arithmetischen und → BitLevel-Operatoren anwenden. Das Beispiel verwendet die UND-Funktion mit der Maske 255.255.255.0 (das entspricht hex 0xFFFFFF00, alternativ kann auch die Maske mit ipv4_to_int codiert werden). Zuletzt wird das Ergebnis in einen String verwandelt (z.B. zur Ausgabe). |
Erzeugung einer Basis-Adresse der
→ Klasse C aus der Adresse eines PC:
$s = '192.168.123.45';
ergibt den String
$m = '255.255.255.0'; $ip = ipv4_to_int($s); $im = ipv4_to_int($m); $bip = $ip & $m; $b = iip4_to_string($bip); $b = '192.168.123.0';
|
Umwandlung Ganze Zahl → StringDie gezeigte PHP-Funktion verwendet zwar keine Regulären Ausdrücke, gehört jedoch sinngemäß hierher.Man kann diese Funktion verwenden, um nach der internen Verarbeitung aus ganzzahligen IPv4-Adressen Strings in der üblichen Formatierung zu erzeugen. Die Funktion verwandelt (ungeprüfte) ganze Zahlen 0..$iip..4244897280 in Strings der Form 11.22.33.44 |
Umwandlung einer ganzzahligen IPv4-Adresse in einen String (Beispiel als
PHP-Funktion):
function iipv4_to_string($iip) {
$ipv4="";
}
$rest = $iip; for($i=3;$i>=0;$i--) {
$mul = pow(256,$i);
}$dig = floor($rest/$mul); $ipv4.=$dig; if($i>0) {$ipv4.='.';} $rest = $rest - $dig * $mul; return $ipv4; |
Filter für ifconfig / ipconfigDas Beispiel zeigt, wie man aus dem Rückgabe-Text der Konsolen-Befehle ifconfig (Linux) bzw. ipconfig die IPv4-Adressen ausfiltert.Zunächst wird mit Hilfe von RegExp entschieden, ob es sich um ein Linux- oder ein Windows-System handelt. Je nach Ergebnis wird der entsprechende System-Befehl $s ausgewählt und ein RegExp in der Variablen $re gespeichert, Danach wird der System-Befehl $s mit dem Operator qx erteilt und der Rückgabe-Text in ein Array von Zeilen @za aufgeteilt. Jede Zeile $z wird mit dem RegExp $re geprüft, welcher nebenbei auch die allenfalls enthaltene IPv4-Adresse in der Variablen $1 isoliert. Die erhaltenen IP-Adressen $ip werden zusätzlich gefiltert: Die immer angezeigte Adresse 127.0.0.1 (localhost) wird ausgeschieden, alle anderen IP-Adressen angezeigt. Das Programm arbeitet problemlos mit allen gängigen Linux- und Windows-Systemen. Die Filter $re sind jedoch empfindlich von der jeweiligen System-Version und -Sprache abhängig und müssen daher evtl. angepasst werden. |
my $sysname = ucfirst($^O);
my($ip,$re,$z,@za); my $s = ''; if($sysname=~m/linux/i) {
$s = 'ifconfig';
}$re = 'inet addr:([\.\d]*)'; elsif($sysname=~m/win/i) {
$s = 'ipconfig';
}$re='IP-Adresse[^\d]*([\d]{1}[\.\d]*)' if($s) {
@za = split(/[\n\r]/,qx($t));
}
foreach $z(@za) {
if($z=~m/$re/) {
}
$ip = $1;
}
if(!($ip=~m/^127\./)) { print "IPv4 = $ip \n";
}
|
RegExp mit XML und HTML (Auszeichnungs-Sprachen) |
|
|
Auszeichnungs-Sprachen verwenden <tags>
(Auszeichnungs-Elemente), das sind bestimmte Text-Marken in
<> Klammern. → XML verlangt streng, dass diese abgeschlossen sind, d.h. entweder als einzelnes <tag \> oder als Paar <tag>..</tag>. Zwischen den Text-Marken befinden sich die Daten. Typische Beispiele sind z.B. → HTML, → XHTML, → SVG u.a. |
Zur XML-Verarbeitung bieten alle modernen Programmiersprachen sog. Parser-Funktionen.
Damit wird ein XML-Objektbaum insgesamt oder sequentiell 'verarbeitet'. Beispiel: → XML-Parsing mit PHP. RegExp-Methoden werden daher nur in Sonderfällen eingesetzt. |
|
Das Beispiel bietet 3 Beispiele $t zur Analyse an: Ein einfaches tag <a> mit Daten, zwei verschachtelte tags <a> und <b> mit Daten, sowie ein tag <a> mit Attribut. ● Die gezeigten RegExp isolieren jeweils den gesamten Inhalt zwischen den tags <a> bzw. <b>, d.h. sowohl Daten als auch andere darin enthaltene tags. ● Ein wichtiges Detail ist der ? Operator im Speicher-Teil (.*?) Er 'dämpft' die Gier des * Operators, der ansonsten nicht nur den Inhalt sondern auch das Ende des tags abdecken würde. ● XML-tags sollten eigentlich nur als Klein-Buchstaben vorliegen, es ist aber gute Praxis, die RegExp mit nachgestellter Flag i case-independant zu erstellen. |
$t = '<a>123</a>';
# $t = "<a>123<b>456</b>789</a>";
if($s=~m/<a[^>]*>(.*?)<\/a>/i) {
# $t = "<a att=\"xyz\">123 456</a>"; print "a = $1\n";
}if($s=~m/<b[^>]*>(.*?)<\/b>/i) { print "b = $1\n";
}
|
Entfernung von Mehrfach-LeerzeichenDiese RegExp ersetzt alle Mehrfach-Leerzeichen und -Tabs durch einfache Leerzeichen. Die while-Schleife enthält keinen Code, weil die gesamte Arbeit bereits im Bedingungs-Teil erledigt wird. |
while($txt=~s/\s\s/ /) {}
|
HTML-Codierung von HTML/XML-QuelltextRechts ein Javascript-Beispiel für die Umwandlung von HTML- oder XML-Quelltext zur Ausgabe auf Webseiten.Zuerst werden alle im Quelltext vorkommenden HTML-maskierten Zeichen wie & € usw. abgefangen, und ihr & in ein & HTML-codiert. Danach kann man Sonderzeichen wie < " > in die HTML-maskierten Strings < " > umgewandeln. Das Beispiel € erfordert den HTML-Quelltext
<span style="color:#F00;">€</span>
und wird mit encode_html in diesen Text umgewandelt
<span style="color:#F00;"> &euro;
</span>
der bei Ausgabe auf einer Webseite den HTML-Quelltext korrekt anzeigt
(Beispiel mit Leerzeichen gegliedert)
|
Javascript
function encode_html(txt) {
txt=txt.replace(/(\&)/g,"&");
}
txt=txt.replace(/(\")/g,"""); txt=txt.replace(/(<)/g,"<"); txt=txt.replace(/(>)/g,">"); return txt; |
|
Diese Funktion sucht in einem Text nach verschiedenen Mustern und formatiert
jeden Treffer für die Ausgabe auf einer Webseite. Zur Formatierung
werden <span>-Elemente und CSS-Klassen verwendet. Das Beispiel demonstriert die Verwendung einer 'back reference': Jeder Treffer wird mit $1 im replace-String weiter verwendet. Beispiel: Aus einem HTML-Formular wird der Text t="a<b c=d" und die Zahl z="123" abgesendet. Das ergibt den → URI-String (Browser-Befehlszeile)
ziel.htm?t=a%3Cb+c%3Dd&z=3
Um den String leichter lesbar zu machen, wird er mit
PHP-Funktion highlight_string in diese Form codiert:
ziel.htm?t=a%3Cb+c%3Dd&z=3
|
Javascript
function hilite(txt) {
// ? & -> rot
txt=txt.replace(/([\?\&])/g,"<span
class='r'>$1</span>");
// %XX -> grün
txt=txt.replace(/(\%[0-9A-F]{2})/g,"<span
class='g'>$1</span>");
// + -> grün
txt=txt.replace(/(\+)/g,"<span
class='g'>$1</span>");return txt; |