Bruno: Mustererkennung in Texten - Textblöcke separieren

hallo liebe forumgemeinde und perl freaks,

ich lese nun schon sehr lange in diesem forum und habe hier schon oft interessante problemlösungen gefunden.
heute allerdings möchte ich euch das erste mal bitten mir zu helfen - ich habe im moment eine kleine "hirnblockade" :)

das problem:
mein script liesst ein word-dokument per OLE aus und stopft den inhalt in ein array.
wenn ich mir dieses array mittels "foreach" ansehe, dann sieht es so aus, wie der auszug weiter unten.

ich möchte jetzt die einzelnen textblöcke weiter verarbeiten.
also jeder dieser blöcke hat eine überschrift und eine beschreibung.
getrennt werden die blöcke mit leerzeilen, manchmal auch einige hintereinander (im beispiel zu sehen).

kann mir bitte jemand eine kleine routine zeigen (oder ansatzpunkte), welche mir block für block zur weiterverarbeitung zur verfügung stellt?
wichtig ist, das die leerzeilen sauber erkannt und als trenner benutzt werden.

in den übergebenen blöcken sollen dann allerdings keine leerzeilen mehr sein.

für eure hilfe möchte ich mich jetzt schon bedanken!!!

viele grüße,
bruno

------------------------------------------------------------------
Nicht von dieser Welt
Italien  1999  100'  R: Giuseppe Piccioni
D: Margherita Buy, Silvio Orlando, Carolina Freschi

Brot und Tulpen
Italien  2000  F  118'  R: Silvio Soldini
D: Licia Maglietta, Bruno Ganz, Giuseppa Battiston

Ayurveda
D/Indien  2000  F  102'  R: Pan Nalin
Der Film bietet eine intensive und sehr sinnliche Reise...

Mio, mein Mio
SU/Schweden/Norwegen  1987  F  95'
Phantasievoll und spannend sind die Abenteuer, die der 9jährige...
------------------------------------------------------------------

  1. Hallo Bruno

    Nicht von dieser Welt Italien  1999  100'  R: Giuseppe Piccioni D: Margherita Buy, Silvio Orlando, Carolina Freschi

    Brot und Tulpen Italien  2000  F  118'  R: Silvio Soldini D: Licia Maglietta, Bruno Ganz, Giuseppa Battiston

    Ayurveda D/Indien  2000  F  102'  R: Pan Nalin Der Film bietet eine intensive und sehr sinnliche Reise...

    Jede Zeile ist ein element in einem Array? wenn ja + sagen wir, es ist das Array @a, dann erst mal einen String draus machen:

    my $s = join('', @a);

    dann Splitten mit mindestens zwei Leerzeilen als Seperator:

    my @splitted = split(/\n\n+/, $s); oder kompakter: my @splitted = split(/\n\n+/, join('', @a));

    in @splitted steht jetzt jeweils ein Block als String (also mit Zeilenumbrüchen), also:

    $splitted[0] ist: "Brot und Tulpen Italien  2000  F  118'  R: Silvio Soldini D: Licia Maglietta, Bruno Ganz, Giuseppa Battiston" (sollte zumindest sein ;)

    das kannst du dann weiter splitten z.B.

    my @item_splitted = split(/n/, $splitted[$i]); z.B. $item_splitted[1] ist dann "Italien  2000  F  118'  R: Silvio Soldini"

    Mit einem herzlichen RTFM! (man perlfunc)

    K@rl

    1. PS:

      ... wieder was vergessen:

      ich gehe davon aus, daß jedes Element in @a ein abschließendes Newline "\n" hat - auch die leeren Zeilen; wenn nicht, dann ändern:

      my $s = join("\n", @a);

      1. hallö k@rl,

        klapp nicht... nicht so richtig :(

        -122 elemente werden ins array gepackt
        -jedes hat ein \n

        dein routinchen bringt mit erkennung von zwei leerzeilen den kompletten inhalt des ausgangs-arrays.
        mit einem \n weniger zumindest weniger - aber nicht richtig.

        es ist für mich schwierig eine genaue beschreibung abzuliefern, sorry.

        könnte ich vielleicht den inhalt des word-dokumentes statt ins array in eine datei schreiben und dir schicken?
        das würde den vorteil haben, das du den gesamten inhalt siehst - ich kann es hier ja nicht so recht posten :)

        viele grüße,
        bruno

        ps: diese sache ist für mich sehr wichtig, denn das programm soll schnellstens fertig werden (ist wohl meistens so).
        den ersten teil des programms habe ich schon fertig und es läuft wunderbar. dort wird eine excel-tabelle ausgelesen und alle daten (datum, uhrzeit, filmtitel) werden sauber in eine html-datei sortiert und geschrieben. das ich jetzt bei so einer text-geschichte auch noch verblöde.... nee nee ;)

        1. hallo liebe leute,

          ich habe hier mal einen längeren auszug des textes als .ZIP file zum download gelinkt.
          damit ist mein problem vielleicht besser verständlich.

          http://217.199.17.184/kino.zip

          ich hoffe immer noch auf eure hilfe :->

          viele grüße,
          bruno

          1. man bin ich blöd!

            das war ein zahlendreher - hier der richtige link:

            http://217.199.71.184/kino.zip

            1. Hallo Bruno

              also, normalerweise mach' ich sowas ja nicht ...

              Das Problem liegt in Deinen Eingabedaten!! Sieh Dir mal die Datei mit einem Hex-Editor an und Du wirst feststellen, daß Du teilweise (immer?) am Zeilenende "\x0d\x0d\x0a" mit zum Teil vorangestellten Schrott hast :-((

              Das hier Funktioniert bei mir (WinDOS Maschine mit ActivePerl):

              1. use strict;  2. my $infile = $ARGV[0] || "kino.txt";  3. open FH, "$infile" or die "cannot open $infile - $!";  4. binmode FH;  5. my @in = <FH>; # slurp!  6. close FH;

              7. # -- clean the \0d\0d\a... mess ...  8. my @cleaned;  9. foreach (@in) { 10.     s/\s+$/\n/; 11.     push @cleaned, $_; 12.     } 13. undef @in; # not needed anymore -> free some RAM 14. # -- END clean

              1. my $joined = join('', @cleaned);

              2. my @splitted = split(/\n\n+/, $joined);

              3. undef $joined; # not needed anymore -> free some RAM

              4. -- BEGIN TEST

              5. my $i = 0;

              6. foreach (@splitted) { 21.     printf "%4d:: %s\nEND-OF-RECORD\n", $i++, $_; 22.     }

              7. -- BEGIN TEST

              Beachte:

              Zeile 3: möglicherweise wird das o-p-e-n im Forum irgendwie          als "/pen" dargestellt Zeile 4: binmode - wegen des Schrotts .. Zeilen 7-14: hier wird der Schrott entfernt - gibt sicher              elegantere Wege das zu tun, aber es macht Zeilen 15-17: wie gesagt - bei sauberen Eingabedaten               ist das ein Weg (remember: TIMTOWTDI!)               - oder 15+16 in einem Befehl - wie vorher               im Thread beschrieben

              In @splitted stehen die jeweiligen Records. Beachte, daß zwar innerhalb jedes Records Zeilenumbrüche "\n" vorhanden sind, welche die Zeilen trennen, aber am Ende kein "\n" steht (was Dir beim Weiterverarbeiten eher nutzen sollte).

              Die ersten beiden Records sind dann bei mir als Output des Tests (möglicherweise werden hier im Forum Deine Deutschen Hoch-Tief-Anführungsstriche nicht richtig dargestellt):

              0:: Nicht von dieser Welt Italien  1999  100'  R: Giuseppe Piccioni D: Margherita Buy, Silvio Orlando, Carolina Freschi Auf der Suche eines Findelkindes kommen sich ein menschenscheuer Wäschereibesitzer und eine idealistische katholische Ordensschwester langsam näher. Am Ende haben die beiden nicht nur die Mutter, sondern auch noch sich selbst gefunden. - Eine Geschichte mit emotionaler Kraft und komödiantischer Leichtigkeit. „Herzergreifende Geschichten im Stile des Neorealismus - Giuseppe Piccionis kleines Meisterwerk scheint dort anzuschließen, wo ‚Brot und Tulpen' aufhört.“ (Frankfurter Rundschau) „Ein kleines Juwel ... völlig zu Recht mit internationalen Auszeichnungen überhäuft.“ (Filmecho) „... erstaunlich ... bewegend. ‚Nicht von dieser Welt' hat genug Klugheit, Feingefühl und Herz für jeden, der ‚Brot und Tulpen' liebt.“ (Der Spiegel) Nominierung für den Oscar „Bester nicht englisch-sprachiger Film“ 2000.

                 1:: Brot und Tulpen
              Italien  2000  F  118'  R: Silvio Soldini
              D: Licia Maglietta, Bruno Ganz, Giuseppa Battiston
              Als Rosalba, eine Hausfrau aus Pescara, an einer Raststätte den Bus verpaßt und Mann und Söhne sie erst nach einiger Zeit vermissen, beginnt für sie ein neues Leben. Per Anhalter landet sie in Venedig, wo sie bei einem etwas verschrobenen, aber liebenswerten Schöngeist und Kellner nicht nur eine billige Bleibe, sondern allmählich auch Zuneigung findet. - Der Film ist nahezu mit allen Preisen ausgezeichnet worden, die Italien zu bieten hat. Aber auch hierzulande sind Publikum und Kritik in ihrer Wertschätzung einer Meinung.
              „Am Ende ... ist jeder glücklich. Vor allem der Zuschauer.“ (FAZ)
              „... wunderschön. Und liebevoll. Und sehr komisch.“ (Die Welt)
              „... romantische Komödie von klassischem Format.“ (Der Tagesspiegel)
              ~~~~END-OF-RECORD~~~~
              
              Gute Nacht!
                  K@rl
              
              
              PS: "GIGO" steht für "Garbage In - Garbage Out"
              
              PPS: "Amelie" halte ich für einen überbewerteten Film
              
              1. moin k@rl,

                juuuubel!!! es geht - ich könnt dich knutschen :>
                wow - werd ich jetzt gut schlafen...

                also, normalerweise mach' ich sowas ja nicht ...

                ...sieh es als tägliche gute tat an *g*, ich wäre dran fast verzweifelt!

                Das Problem liegt in Deinen Eingabedaten!!
                Sieh Dir mal die Datei mit einem Hex-Editor
                an und Du wirst feststellen, daß Du teilweise
                (immer?) am Zeilenende "\x0d\x0d\x0a"
                mit zum Teil vorangestellten Schrott hast :-((

                ...das hat das Win32::OLE modul produziert  - sorry :(

                PPS: "Amelie" halte ich für einen überbewerteten Film

                :)))))
                ich habe diese kritiken zum glück nicht geschrieben.

                yo k@rl, dann danke ich dir nochmals recht herzlich für die freundliche und sehr schnelle hilfe.
                auch allen anderen, die mir helfen wollten gilt mein dank!

                viele grüße aus berlin und allen eine gute nacht,
                bruno

  2. use Mosche;

    kann mir bitte jemand eine kleine routine zeigen (oder ansatzpunkte), welche mir block für block zur weiterverarbeitung zur verfügung stellt?
    wichtig ist, das die leerzeilen sauber erkannt und als trenner benutzt werden.

    in den übergebenen blöcken sollen dann allerdings keine leerzeilen mehr sein.

    Mein Ansatz geht davon aus, dass ein eintelner Block in drei hintereinander folgenden Zeilen steht (nur zw. den Blöcken Leerzeilen, nicht im Block).
    Er macht grundsätzlich folgendes:
    er liest aus deinem Array ein.
    Wenn er eine Spalte ohne Text erwischt, überspringt er sie.
    Ansonsten hat er die erste Zeile.
    Dann liest er noch zwei Zeilen ein, und hat damit den kompletten Block. danach gehts weiter.

    my @block;
    while(defined(my $line = shift @lines)) {
     my %eintrag;
     next if $line =~ m/^\s*$/; # leere Zeilen überspringen
           # Zeilen, die nichts als
           # Leerzeichen und Tabs enthalten

    # Wenn wir hier sind, haben wir die Überschrift
     $eintrag{'titel'} = $line;

    # das hier musst du machen,
     # wird nen komplizierter regex.
     # ich weiss nicht, nach welchen
     # Kriterien du das ordnen willst.
     my ($land, $jahr, ...) = split(/\s+/, shift @lines);

    # jetzt die dritte Zeile (Darsteller)
     $eintrag{'darsteller'} = shift @lines;
    }

    use Tschoe qw(Matti);

  3. hallo matti & k@rl,

    ihr seit ja fix - hut ab und vielen dank für das hirnfutter!
    werd gleich mal ein paar tests machen...

    matti, die blöcke bestehen leider nicht aus 3 zeilen.
    das dokument ist 3 meter lang und jeder block 10 bis 30 zeilen :)

    so denn, ich mach dann mal.

    liebe grüße,
    bruno

  4. Hallo,

    das problem:
    mein script liesst ein word-dokument per OLE aus und stopft den inhalt in ein array.

    ich würde gleich beim Einlesen die Aufteilung machen. Etwa

    <code>
    my $block_count = 0;
    my @blocks;
    my $line
    while(&get_line_from_worddocument($line))
      {
      chomp; # Frage: ist \n wirklich Bestandteil der Zeilen?
      $line =~ s/\s*$//; # eventuell Leerzeichen rausschmeißen

    jetzt sind wir uns sicher, daß nix mehr in den Leerzeilen stehen kann

    if($line eq '')
        {
        $block_count++;
        }
      else
        {
        push @{$blocks[$block_count]}, $line;
        }
      }
    </code>

    Damit ersparst Du Dir zumindest ein Array, daß eigentlich nur einmal gebraucht wird.

    'Literaturhinweis':
    perldoc perllol
    perldoc perldsc

    Grüße
      Klaus

    1. moin klaus,

      vielen dank für deine hilfe - habs gerade ausprobiert.
      leider auch nicht das richtige.

      zumindest passiert folgendes bei mir:

      -leerzeilen werden rausgenommen (ok)
      -jede zeile mit inhalt stellt jetzt ein element im array dar :(

      es soll ja jeder block (der durch leerzeilen getrennt ist/war) ein element sein.

      anbei nochmal ein auszug des textes, der bearbeitet werden soll zum download:

      http://217.199.71.184/kino.zip

      viele grüße,
      bruno