PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Brauche Hilfe bei einer Regular-Expression


dav133
2009-06-11, 11:14:32
Hallo,

Ich habe einen Input in folgendem Format in einer Datei als Text vorliegen, auf dessen Formatierung ich keinen Einfluss habe:


tag3="01.06.09|25456;4548|17635;3010|17479;3010|17709;3009|17555;3006|16789;2977|17337 ;2995"
tag2="31.05.09|28171;4672|19398;3009|19247;3010|19405;3003|19274;3010|18796;3009|18858 ;302"
tag1="30.05.09|30163;4632|20720;3009|20600;3004|20756;3009|20636;3002|19277;3007|20060 ;3007"


/edit: Das ganze kann beliebig so weitergehen, der String kann also auch aus 25 Wertepaaren pro Zeile bestehen, sodass ich keine "immer passende" Regex ansetzen kann. Siehe dazu meinen zweiten Post.

Nun würde ich das Ganze zur Weiterverarbeitung mit PHP gerne in ein "lesbares" Format überführen, welches

1) das Datum und
2) jeden zweiten Wert (also den hinter dem Semikolon)

enthält, ich habe mal fett markiert, was ich benötige:



tag3="01.06.09|25456;4548|17635;3010|17479;3010|17709;3009|17555;3006|16789;2977|17337 ;2995"
tag2="31.05.09|28171;4672|19398;3009|19247;3010|19405;3003|19274;3010|18796;3009|18858 ;302"
tag1="30.05.09|30163;4632|20720;3009|20600;3004|20756;3009|20636;3002|19277;3007|20060 ;3007"


Im Optimalfall hätte ich also gern ein Array, welches etwa folgende Struktur hat:



Array
(
[0] => Array
(
[0] => 01.06.09
[1] => 4548
[2] => 3010
[3] => 3010
[4] => 3009
[5] => 3006
[6] => 2977
[7] => 2955
)

[1] => Array
(
[0] => 31.05.09
[1] => 4672
[2] => 3009
[3] => 3010
[4] => 3003
[5] => 3010
[6] => 3009
[7] => 302
)

[2] => Array
(
[0] => 30.05.09
[1] => 4632
[2] => 3009
[3] => 3004
[4] => 3009
[5] => 3002
[6] => 3007
[7] => 3007
)
)



Die Regex sollte nach Möglichkeit recht "performant" sein, da es sich um größere Datenmengen handelt. Wäre für Hilfe sehr dankbar ;).

lg

Tiamat
2009-06-11, 16:29:01
Also ich mach mal den Anfang. Das aufwändigste ist hier das Überprüfen des Datums, wenn du das korrekt angehen willst.
Sowas wie [0-9]{1,2}[.-/][0-9]{1,2}[.-/][0-9]{2,4} funktioniert nur wenn du auf das korrekte Datum pfeifst.


So da du jetzt weißt, in welche Richtung das ganze läuft, brauchst nur nur noch folgende Fälle berücksichtigen
Wenn Monatstag mit 3 anfängt , dann zweite Ziffer 0-1 ODER
Monatstag 0, dann NICHT 0
SONST [1-2][0-9]

TRENNZEICHEN [.-/]

Wenn Monat 0 dann NICHT 0 als Zweite Ziffer
sonst nur von 1-2 als zweite Stelle.

TRENNZEICHEN [.-/]

e.t.c

Schaltjahre prüfen mit Februar und korrekte Monatsbelegung dürfte etwas aufwändiger sein.

Die Lösung für die Zahlen nach dem Datum ist einfach :
[0-9]{3,4} {mindestvorkommen,maximalvorkommen}

Es kommt ganz auf deine Ansprüche an.

Gruß
Tiamat

dav133
2009-06-11, 18:39:01
Also ich mach mal den Anfang. Das aufwändigste ist hier das Überprüfen des Datums, wenn du das korrekt angehen willst.
Sowas wie [0-9]{1,2}[.-/][0-9]{1,2}[.-/][0-9]{2,4} funktioniert nur wenn du auf das korrekte Datum pfeifst.


So da du jetzt weißt, in welche Richtung das ganze läuft, brauchst nur nur noch folgende Fälle berücksichtigen
Wenn Monatstag mit 3 anfängt , dann zweite Ziffer 0-1 ODER
Monatstag 0, dann NICHT 0
SONST [1-2][0-9]

TRENNZEICHEN [.-/]

Wenn Monat 0 dann NICHT 0 als Zweite Ziffer
sonst nur von 1-2 als zweite Stelle.

TRENNZEICHEN [.-/]

e.t.c

Schaltjahre prüfen mit Februar und korrekte Monatsbelegung dürfte etwas aufwändiger sein.

Die Lösung für die Zahlen nach dem Datum ist einfach :
[0-9]{3,4} {mindestvorkommen,maximalvorkommen}

Es kommt ganz auf deine Ansprüche an.

Gruß
Tiamat


Hi, danke erstmal für deine Antwort.

warum denn so kompliziert? Für das Datum würde es \d{2}\.\d{2}\.\d{2} vollkommen tun, da die Syntax des Datums immer die gleiche ist. Und abzufangen, dass etwa der 32.13.1337 als Datum drinsteht, ist nicht notwendig, da der Input "verlässlich" ist. Mein Problem sind nun aber genau die Zahlen, da der String beliebig lang sein kann.

Mir schwebte etwas wie

/(\d{2}\.\d{2}\.\d{2})(\|\d+;(\d+))+/i

vor, allerdings ist da das Problem, dass der letzte Pattern sich nicht "automatisch" wiederholt, bräuchte also wie eine Art Schleife... Blöd zu erklären.

lg

rotalever
2009-06-12, 14:06:39
Da du ja nichts überprüfen willst, würde ich gar nicht erst regex nehmen...
Eher so:

$tage = // einlesen der Datei zeilenweise in ein Array ohne Line-Ending (dafür gibt es irgendeinen Befehl (file?)

$anzahl = sizeof($tage);
for ($i = 0; $i < $anzahl; ++$i)
{
$begin = strpos($tage[i], "\"")+1;
$tage[i] = explode("|", substr($tage[i], $begin, -1));
$w_anzahl = sizeof($tage[i]);
for($j = 1; $j < $w_anzahl; $j++)
{
$tage[i][j] = substr($tage[i][j], strpos($tage[i][j], ";")+1);
}
}

Geht das so? Das Format muss natürlich exakt stimmen.

edit: 0 durch 1 ersetzt...

Gast
2009-06-12, 14:33:53
einlesen der Datei zeilenweise in ein Array ohne Line-Ending (dafür gibt es irgendeinen Befehl (file?)


Jo ist file () aber das liest die Zeilenendungen mit ein.
Also dann sowas wie hier verwenden:

function trim_lineendings(&$value)
{
$value = trim($value,"\r\n");
}
$tage = file ("datei.txt");
array_walk($tage, 'trim_lineendings');

dav133
2009-06-12, 14:58:44
hallo, danke euch zweien... mein bisheriger Weg sieht so aus:


$input=file_get_contents('months.js');
//alles zwischen den hochkommas
preg_match_all('/\"(.*?)\"/im',$input,$out);
//nur die fundstellen aus regex
$out=$out[1];
$lineCount=count($out);
for($i=0;$i<$lineCount;$i++)
{
$out[$i]=explode('|',$out[$i]);
}
echo "<pre>".print_r($out,true)."</pre>";

Ich dachte mir nur halt, dass man es (wenn man schon mit reg-exps macht) auch komplett damit erledigen kann...

lg

/edit: irgendwie scheine ich blos das Prinzip von Regexps nicht ganz durchblickt zu haben...

preg_match_all('/([a-z]+;)+/','das;sind;alles;woerter;',$out);

erzeugt den Output


Array
(
[0] => Array
(
[0] => das;sind;alles;woerter;
)

[1] => Array
(
[0] => woerter;
)

)


...und findet somit nach meinem Verständnis nur das letzte von vielen Wörtern - Ich würde mir wiederum ein Array mit allen gefundenen Wörtern erwarten -- komisch

rotalever
2009-06-12, 15:10:19
Jo ist file () aber das liest die Zeilenendungen mit ein.

Nicht wenn man die richtige Flag verwendet (FILE_IGNORE_NEW_LINES).

Gast
2009-06-12, 15:30:25
http://de.php.net/manual/de/function.file.php
Also da steht absolut nix davon das man irgendwelche Flags mitgeben kann.

rotalever
2009-06-12, 16:45:04
http://de.php.net/manual/de/function.file.php
Also da steht absolut nix davon das man irgendwelche Flags mitgeben kann.
:| Das kann nicht sein. Ich habe es vorhin noch nachgeschaut. In den Kommentaren steht da auch was von.
Ok: "Last updated: Fri, 12 Jun 2009"
Webarchive sagt:
http://web.archive.org/web/20071026013750/http://de2.php.net/function.file
Also haben die das da grade rausgelöscht oder wie? Sehr seltsam..

edit: Ah ok... Man muss sich die Seite auf Englisch anschauen...
http://de2.php.net/manual/en/function.file.php