FHEM Forum

Verschiedenes => Off-Topic => Thema gestartet von: DarkT am 09 Februar 2018, 11:45:56

Titel: Perl / Regex Anfängerfrage
Beitrag von: DarkT am 09 Februar 2018, 11:45:56
Hallo zusammen,

ich habe eine Frage zu Perl/Regex und würde da gerne mal eure Expertise ansprechen.

Ich habe eine Webseite, die wie folgt aufgebaut ist:


<tr class="tr-even tr-6">
<td class="td-0">BL </td>
<td class="td-1">23.</td>
        <td class="td-2">18.02.2018</td>
<td class="td-3">So.</td>
<td class="td-4">18.00</td>
<td class="td-5"><img src="/fileadmin/templates/main/image/wappen/mgladbach.png"/></td>
<td class="td-6">Borussia</td>
<td class="td-7"> <img src="/fileadmin/templates/main/image/wappen/dortmund.png"/></td>
<td class="td-8">Borussia Dortmund </td>
<td class="td-last td-9">-:- <a href="de/team-saison/die-fohlenelf/spielplan.html#"class spielbericht disabled "> </a></td>
</tr>


Diese <tr>-Abschnitte wiederholen sich halt für jedes Spiel.

Ich würde jetzt gerne die Roh-Daten auslesen, so das ich die Form:


26.08.2017 15.30 FC Augsburg -  Borussia
09.09.2017 15.30 Borussia - Eintracht Frankfurt
16.09.2017 18.30 RB Leipzig -  Borussia
19.09.2017 18.30 Borussia - VfB Stuttgart
23.09.2017 18.30 Borussia Dortmund -  Borussia
30.09.2017 15.30 Borussia - Hannover 96


erhalte. Dazu habe ich ein kleines perl-Program geschrieben. Leider sind sowohl meine perl als auch meine Regex Erfahrungen noch sehr beschränkt.
Also ist das folgende raus gekommen:


use strict;
use warnings;

sub  trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
my $filename = "spielplan.html";

open(my $fh, '<:encoding(UTF-8)', $filename)
  or die "File not opened";

my $content = "";

while (my $row = <$fh>) {
   chomp $row;
   $content .= $row;
}
my $onerow;

while ($content =~ /(?:class="td-2">)([1-90]{2}.[1-90]{2}.[1-90]{4})|(?:class="td-4">)([1-90]{1,2}.[1-90]{2})|(?:class="td-6">)([[:print:]]*)(?:[<])|(?:class="td-8">)([[:print:]]*)(?:[<])/g)
{
  if (defined $1) {
    $onerow .= trim($1);
  }
  if (defined $2) {
    $onerow .= " " . trim($2);
  }
  if (defined $3) {
    $onerow .= " " . trim($3);
  }
  if (defined $4) {

      $onerow .= " - " . $4 . "\r\n";
      print ("$onerow");
      $onerow = "";
  }
}


Das fühlt sich aber irgendwie nicht richtig an. Vor allem der Teil mit den if (defined $X ).

Wie kann man sowas besser lösen?
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: DarkT am 09 Februar 2018, 18:45:21
Ist das hier das falsche Forum?
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: JoWiemann am 09 Februar 2018, 19:25:38
Nur Geduld. Vielleicht können die Dortmunder ja kein RegEx & Perl und die Bayern wollen nicht helfen.

Duck und weg...
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: DarkT am 09 Februar 2018, 20:08:46
Ja, stimmt, das ist bestimmt die Erklärung  :D
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: DarkT am 10 Februar 2018, 11:44:50
Ok,
vielleicht ist die Frage zu komplex. Dann mal anders

Wie kann man in perl einen String parsen, wobei im regulären Asudruck mehrere Gruppen auftreten.

Beispiel


regex: ([a-z]{2})([1-9]{2})
string: ab12cd34ef56
Ausgabe: ab12, cd34, ef56


Ich hätte also gerne in jedem Schleifendurchlauf jeweils des Paar ab und 12, bzw cd und 34 und dann ef und 56

Hat da jemand einen Codeschnipsel für?

Danke schon mal
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: KernSani am 10 Februar 2018, 13:19:02
Bin mir jetzt nicht gan sicher, ob ich das richtig verstanden habe, aber die Rückgabe der regex sollte in $1 stehen...


Kurz, weil mobil...
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: DarkT am 10 Februar 2018, 15:57:15
Ja ... mit $1 und $2 kann man auf die Gruppen zugreifen, aber bei dem folgenden Beispiel



regex: (?:Name:)([a-z]{5}) | (?:ID:)([1-9]{5}) /g
string: Name:ABCDE .... ID:12345 ..... Name:GHIJK .... ID: 67890
Ausgabe: ABCDE, 12345 und GHIJK, 67890



wie mache ich es da? So dass ich die Ausgabe erhalte.

Will halt alle Name, ID Paare finden
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: KernSani am 10 Februar 2018, 16:15:07
Mal mit einem array probiert?
my @matches = ( $s =~ /regex/g);
Oder so ähnlich müsste gehen...


Kurz, weil mobil...
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: DarkT am 10 Februar 2018, 16:37:06
Das hab ich probiert. Problem ist, das in jedem Schleifendurchlauf nur EINE der $1, $2 gesetzt ist.
Dachte das geht irgendwie schlauer .... ?

Ansonsten muss man zur Zeit immer sammeln bis das letzte zu erkennende Element (hier ID) vorbei kommt und kann erst dann seine Aktion durchführen.

Das ganze ist natürlich dem regulären Ausdruck mit ,,|" geschuldet.
Gäbe es sowas wie:

,,Nimm das wort hinter Name, sich dann weiter bis ID und nimm die Zahl dahinter"

Dann wäre das sicherlich einfacher.
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: Phill am 11 Februar 2018, 00:13:30
Wenn du zu dem Modifier "g" noch "s" hinzugügst, treffen Newlines auch auf ".". Somit würde wenn du deine Veroderung "|" durch ".*?" ersetzt, alle Klammern gleichzeitig treffen.

Nur so ein erster Gedanke.
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: Christoph Morrison am 11 Februar 2018, 00:58:46
Zitat von: DarkT am 09 Februar 2018, 11:45:56
Wie kann man sowas besser lösen?

In dem man auf tag soup parsing verzichtet und XPath benutzt. Die XPath-Expressions kannst du einfach z.B. mit den Chrome Developer Tools rausfinden, mit XML::XPath auslesen und bekommst dann eine Liste mit Nodes, über die du dann iterieren und die Details rausfinden kannst.

Zum Beispiel würde //*[@id="content"]/div[2]/table/tbody/tr eine Liste mit Nodes zurückliefern, in der jeder Eintrag eine Partie (Tabellenzeile) beschreibt.
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: DarkT am 11 Februar 2018, 12:00:26
Zitat von: Christoph Morrison am 11 Februar 2018, 00:58:46
In dem man auf tag soup parsing verzichtet und XPath benutzt. Die XPath-Expressions kannst du einfach z.B. mit den Chrome Developer Tools rausfinden, mit XML::XPath auslesen und bekommst dann eine Liste mit Nodes, über die du dann iterieren und die Details rausfinden kannst.

Zum Beispiel würde //*[@id="content"]/div[2]/table/tbody/tr eine Liste mit Nodes zurückliefern, in der jeder Eintrag eine Partie (Tabellenzeile) beschreibt.

Ok, Danke der Ansatz gefällt mir natürlich viel besser, werde ich mal probieren.
Werde mal versuchen, dass auf mein ursprüngliches Problem zu übertragen.
Titel: Antw:Perl / Regex Anfängerfrage
Beitrag von: Christoph Morrison am 11 Februar 2018, 13:30:47
Zitat von: DarkT am 11 Februar 2018, 12:00:26
Ok, Danke der Ansatz gefällt mir natürlich viel besser, werde ich mal probieren.
Werde mal versuchen, dass auf mein ursprüngliches Problem zu übertragen.

HTTPMOD unterstützt übrigens auch XPath.