Perl / Regex Anfängerfrage

Begonnen von DarkT, 09 Februar 2018, 11:45:56

Vorheriges Thema - Nächstes Thema

DarkT

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?

DarkT

Ist das hier das falsche Forum?

JoWiemann

Nur Geduld. Vielleicht können die Dortmunder ja kein RegEx & Perl und die Bayern wollen nicht helfen.

Duck und weg...
Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

DarkT

Ja, stimmt, das ist bestimmt die Erklärung  :D

DarkT

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

KernSani

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...
RasPi: RFXTRX, HM, zigbee2mqtt, mySensors, JeeLink, miLight, squeezbox, Alexa, Siri, ...

DarkT

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

KernSani

Mal mit einem array probiert?
my @matches = ( $s =~ /regex/g);
Oder so ähnlich müsste gehen...


Kurz, weil mobil...
RasPi: RFXTRX, HM, zigbee2mqtt, mySensors, JeeLink, miLight, squeezbox, Alexa, Siri, ...

DarkT

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.

Phill

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.
Homebrew 1-Wire / HomeMatic Mix - Cubietruck mit FHEM als Server - Raspberry PI 3 als Informationsanzeige im MagicMirror Stil - Raspberry Pi 1 als Klingelanlage - VDR

Mein Modul: Talk2Fhem - Mein Tipp: https://forum.fhem.de/index.php/topic,82442.0.html

Christoph Morrison

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.

DarkT

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.

Christoph Morrison

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.