Regulären Ausdruck?

Hallo

ich habe eine Textdatei mit folgenden Inhalt:

msie {n}#####Internet Explorer {n}
windows nt {n}#####MS WIN NT {n}
mozilla/{n}#####Mozilla {n}
… (noch viel mehr davon)

Das lese ich ein, liegt im Array „$data“.

Ich möchte nun den UserAgent (der ist in der Variable „$ua“) überprüfen und bei Übereinstimmung ein neues Array ($uas) mit den Werten füllen.

Beispiel:
„$ua“ enthällt z.b. „Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727;…“

Das neuen Array ($uas) soll nun folgenden Inhalt haben
„Internet Explorer 8.0“
„MS WIN NT 6.1“
„Mozilla 4.0“

Das „{n}“ soll sozusagen übernommen werden. Egal ob im Useragent hier nur Zahlen sind oder auch andere Zeichen. Ein Useragent kann auch ein Inhalt mit „MSIE 6.0b“ haben.

Ich würde das zwar hinbekommen, mit strpos, substr usw. aber wollte mal nachfragen ob das mit solchen regulären ausdrücken und dem entsprechenden befehl dazu auch einfacher zu lösen ist?

Gruß
Michael

Hallo

$ua="Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727;...";
$data = array(
 'msie {n}#####Internet Explorer {n}',
 'windows nt {n}#####MS WIN NT {n}',
 'mozilla/{n}#####Mozilla {n}'
);


$matches=array();
$result=array();

foreach ($data as $replace)
{
 $replace = explode('#####',$replace);
 if (preg\_match('/'.str\_replace(array('{n}','/'),array('([^ ;]+)','\/'),$replace[0]).'/i',$ua,$matches))
 {
 $result[]=(isset($matches[1])) ? str\_replace('{n}',$matches[1],$replace[1]) : $replace[1];
 }
}

Das meiste ist selbsterklärend, nur kurz was zu den regulären Ausdrücken.
In der Perl-kompatiblen Syntax gibt man die als an. Die Delimiter dienen dazu den eigentlichen Regex von den Optionen zu trennen. Hierfür wird meistens / verwendet. Soll dieses Zeichen innerhalb des Regex verwendet werden, muss ein \ vorangestellt werden, also schreibt man dann /.

preg\_match('/'.str\_replace(array('{n}','/'),array('([^ ;]+)','\/'),$replace[0]).'/i',$ua,$matches)

Wenn man hier z.B. die dritte Array-Zeile einsetzt erhält man

preg\_match('/mozilla\/([^ ;]+)/i',$ua,$matches)

Dabei wird überprüft, ob es in $ua einen Teilstring gibt, der mit 'mozilla ’ beginnt und sich dann mit einem oder mehreren Zeichen fortsetzt, die weder Leerzeichen noch Semikolon sind. Wenn ja, dann wird in $matches[0] dieser Teilstring zurückgegeben, in $matches[1] findet man dann den Teilstring, der zum ersten eingeklammerten Bereich des Regex passt, also zu ‚[^ ;]+‘.

[^] steht für ein beliebiges Zeichen, das nicht in enthalten ist.

  • bedeutet, dass das beschriebene Zeichen mindestens einmal vorkommen muss.
    Die Option i schaltet die Berücksichtigung von Groß- und Kleinschreibung ab.

sigterm

Super! Vielen Dank
Damit kann ich schon recht viel anfangen.

Es gibt zwar UserAgents die ein wenig durcheinander sind (wie z.b. zwei MSIE Angaben aber mein $data-array mach ich in diesem Fall so:

msie 1{n}#####IE1{n}
msie 2{n}#####IE2{n}
msie 3{n}#####IE3{n}

Davor noch:

opera {n}#####Opera {n}
opera/{n}#####Opera/{n}
firefox/{n}#####Firefox/{n}

weil gerade diese noch „msie“ mit angeben können.

Ein UserAgent gibt z.b. folgendes an:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [en]

In $result wird dann zwar für das Windows NT am Ende noch das Zeichen „)“ mitgespeichert aber das ist nicht so schlimm. Kann ja nachträglich solche Dinge entfernen. Auch habe ich bei diesem UserAgent in $result ein MSIE und ein Opera. Muss dann noch ein paar IF-Abfragen machen damit am Ende der richtige Browser angezeigt wird.
In diesem Fall Opera 7.23 und Windows 2000.

Also vielen Dank für deine Arbeit. Kann diesen Code auch für andere Dinge gebrauchen.

Michael

Hallo

Es gibt zwar UserAgents die ein wenig durcheinander sind (wie
z.b. zwei MSIE Angaben aber mein $data-array mach ich in
diesem Fall so:

Probier mal das:

foreach ($data as $replace)
{
 $replace = explode('#####',$replace);
 if (preg\_match\_all('/'.str\_replace(array('{n}','/'),array('([^ ;]+)','\/'),$replace[0]).'/i',$ua,$matches, PREG\_SET\_ORDER))
 {
 foreach ($matches as $match)
 $result[]=(isset($match[1])) ? str\_replace('{n}',$match[1],$replace[1]) : $replace[1];
 }
}

Damit sollten auch mehrfache Vorkommen gefunden werden, ohne dass sie mehrfach in der Liste stehen müssen.

In $result wird dann zwar für das Windows NT am Ende noch das
Zeichen „)“ mitgespeichert aber das ist nicht so schlimm.

Ersetze ([^ ;]+) durch ([^ :wink:]+)
Dann werden schließende Klammern ebenso wie Semikolon und Leerzeichen als Ende der Versionsnummer angesehen.

sigterm

Nochmals Danke für deine Hilfe.
Funktioniert einfach spitze!

Michael