################################################################################ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ #### Author(s): Bjoern Wilmsmann #### ### Anfang Pakete einbinden # Pakete zur Fehlerdiagnose use strict; use diagnostics; # Paket zum Anzeigen von Datenstrukturen use Data::Dumper; # Paket zur Anbindung an XFST use XFST::Lookup; # Tokenisierer use Lingua::Tokenize; ### Ende Pakete einbinden ### Variablen definieren # Laufzeiten beim Disambiguieren my $startTime; my $endTime; my $runTime; # Pluralendung bei Sekundenausgabe my $plural; # XFST-Lookup Objekt my $lookup; # Tokenize Objekt my $tokenizer; # Puffer fuer gesamtes Corpus my $wholeCorpus; # Puffer fuer morphologisch zu analysierende Tokens my @tokens; # Puffer fuer morphologisch zu analysierende Types my @types; # Puffer fuer zu disambiguierenden Saetze my @sentencesToBeDisambiguated; # Puffer fuer alle NICHT disambiguierten Kohorten my %cohorts; # Puffer fuer alle disambiguierten Kohorten my %disambiguatedCohorts; # Wert fuer Disambiguierungsdurchlaeufe, entspricht der Anzahl der tatsaechlichen Durchlaeufe - 1, da # ein Durchlauf ohne bereits disambiguierte Kohorten erfolgt my $disambiguationIterations = 4; # Corpusdatei my $corpusFile = "testsatz.txt"; # Pfad zu XFST definieren my $xfstPath = "/opt/xerox-macosx"; ### Ende Variablen definieren ### Anfang Funktionsdefinition # Funktion zum Disambiguieren der Kohorten sub disambiguate { # Puffer fuer einzelne Constraint-Positionen my @constraintBuffer; # Puffer fuer Position und verlangte Lesart an dieser Position my @constraintEnvironmentBuffer; # Puffer fuer Tokens eines Satzes my @thisTokens; # Puffer fuer zu disambiguierende Saetze my @thisSentencesToBeDisambiguated; # Puffer fuer Aenderungsanweisung fuer Lesart my @changeInto; # Puffer fuer Lesartenstrings my @readingInformation; # Puffer fuer Lesartenstrings an Umgebungsposition my @environmentReadingInformation; # Puffer fuer eine Sequenz von Constraints my @thisConstraintCollection; # Puffer fuer alle disambiguierten Kohorten my %disambiguatedCohorts; # Puffer fuer Constraints my %constraints; # Puffer fuer zu disambiguierende Kohorten my %thisCohorts; # Referenz auf eine Kohorte an einer Umgebungsposition my $environmentCohort; # Puffer fuer geaenderte Lesart my $newReading; # Puffer fuer Informationen zu einer bestimmten Lesart my $thisReadingInformation; # Puffer fuer die einzelnen Umgebungsangaben eines Constraints my $thisConstraintEnvironment; # Puffer fuer Lesarten an einer bestimmten Umgebungsposition my $environmentReading; # Puffer fuer den Anfang einer Lesarten-Zeile my $tokenReading; my $tokenEnvironmentReading; # Puffer fuer Constraintzeichenkette my $constraintString; # Flag fuer zu verwerfende Lesarten my $discard; # Flag fuer zu aendernde Lesarten my $change; # Flag fuer Hash-Modus (0=Worte als Kohortenschluessel, 1=Indices als # Kohortenschluessel) my $hashMode = $_[2]; # Modus-Anweisung fuer Constraints: DISCARD_THIS(=0) || # DISCARD_STRICTLY(Komplement von =!!) || DISCARD_OTHERS(=!) || # CHANGE_THIS=*(keine Entsprechung) || DISCARD_THIS_UNLESS(Komplement von =0) # || DISCARD_STRICTLY_UNLESS(=!!) || DISCARD_OTHERS_UNLESS(Komplement von =!) # || CHANGE_THIS_UNLESS=*(keine Entsprechung, Komplement von CHANGE_THIS=*) my $mode; # Satzanzahl my $i = 0; # Tokenanzahl my $j = 0; # Zeiger in der jeweiligen Kohorte my $k = 0; # Flag, das angibt, ob ein Teil eines Constraints einer weiteren Verarbeitung # widerspricht my $contradiction = 0; # Flag, das angibt, ob ein Constraint bereits bestaetigt wurde my $confirmed = 0; # Array fuer Constraintbestandteile my @constraintParts; # Zeiger auf einzelne Constraintbestandteile my $constraintPartCounter; # Dereferenzieren der Saetze auf lokale Werte @thisSentencesToBeDisambiguated = @{$_[0]}; # Dereferenzieren der Kohorten auf lokale Werte %thisCohorts = %{$_[1]}; # Lese Constraints ein %constraints = %{readConstraints ()}; # Analysierte Token disambiguieren, dabei wird satzweise vorgegangen foreach my $thisSentence (@thisSentencesToBeDisambiguated) { # Setze Tokenpointer auf 0 $j = 0; # Einzelne Worte einlesen und ueber diesen iterieren @thisTokens = split (/\s+/, $thisSentence); foreach my $thisToken (@thisTokens) { # Arrays fuer Kohorte definieren my @thisCohort; my @thisCohortBuffer; # Abfrage, ob Hash-Schluessel aus Worten besteht if ($hashMode == 0) { # Selegiere die passende Kohorte fuer dieses Wort, mit dem Wort # als Schluessel, falls eine solche vorhanden ist # und setze ihren Pointer auf Index 0 if (defined (@{$thisCohorts{$thisToken}})) { # Diese Kohorte definieren @thisCohort = @{$thisCohorts{$thisToken}}; } } # Abfrage, ob Hash-Schluessel aus Indices besteht if ($hashMode == 1) { # Selegiere die passende Kohorte fuer dieses Wort, mit dem Index # als Schluessel, falls eine solche vorhanden ist # und setze ihren Pointer auf Index 0 if (defined (@{$thisCohorts{$i . "." . $j}})) { # Diese Kohorte definieren @thisCohort = @{$thisCohorts{$i . "." . $j}}; } } # Kohorte zwischenspeichern @thisCohortBuffer = @thisCohort; # Falls Kohorte gefunden werden konnte if (scalar (@thisCohort) > 0) { # Pointer setzen $k = 0; # Hash fuer bereits bearbeitete Lesarten definieren my %processed; # Hash fuer bereits geaenderte Lesarten definieren my %changed; # Iteriere ueber moegliche Lesarten foreach my $thisReading (@thisCohort) { # Teile Lesartenstrings nach '+' und nutze dann die Constraints mit der # Bezeichnung der morphologischen, syntaktischen Kategorien (z.B. 'NP.txt', # aber auch 'NP+3P+SG.txt'), dazu wird das die Lesart anfuehrende Wort # entfernt ### 1 ### @readingInformation = split (/\+/, $thisReading); $tokenReading = shift (@readingInformation); $constraintString = ""; foreach $thisReadingInformation (@readingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Selegiere die passenden Constraints aus dem Constraint-Hash, falls diese # vorhanden sind if (defined (@{$constraints{$constraintString}})) { # Selegiere Constraints @thisConstraintCollection = @{$constraints{$constraintString}}; # Iteriere ueber Constraints foreach my $thisConstraint (@thisConstraintCollection) { # Setze den Bestaetigungswert zurueck $confirmed = 0; # Teile Constraints nach ' ' auf und speichere den gewuenschten Modus @constraintBuffer = split (/\s+/, $thisConstraint); $mode = shift (@constraintBuffer); # Anfang Modus-Switch # Ab hier wird nach den verschiedenen Modi umgeschaltet # # DISCARD_THIS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus wird genau die behandelte Lesart verworfen, wenn die Bedingungen # erfuellt sind, entspricht =0 if ($mode eq "DISCARD_THIS" && !defined ($processed{$k})) { # Nehme zunaechst an, dass die Lesart nicht geloescht wird $discard = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach my $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten behalte die Lesart if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohorte der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach my $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange die Lesart nicht als zu entfernen markiert ist if ($discard != 1) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintpositionen $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, markiere # diese Lesart als zu verwerfen, ansonsten behalte sie bei if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $contradiction != 1) { $discard = 1; } else { $discard = 0; $contradiction = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position dem Postulat im Constraint entspricht, # markiere sie als zu verwerfen, ansonsten behalte sie bei if ($constraintString eq $constraintEnvironmentBuffer[1]) { $discard = 1; } else { $discard = 0; } } } } } else { $discard = 0; } } # Falls Lesart am Ende des Prozesses als zu verwerfen markiert ist, loesche sie aus der # entsprechenden Kohorte if ($discard == 1 && scalar (@thisCohortBuffer) > 1 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)), 1); $processed{$k} = 1; } } # Ende DISCARD_THIS Modus # DISCARD_THIS_UNLESS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus wird genau die behandelte Lesart verworfen, wenn die Bedingungen # nicht erfuellt sind, entspricht dem Komplement von =0 if ($mode eq "DISCARD_THIS_UNLESS" && !defined ($processed{$k})) { # Nehme zunaechst an, dass die Lesart nicht geloescht wird $discard = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach my $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten entferne die Lesart direkt if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohorte der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach my $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange die Lesart als zu entfernen markiert ist if ($confirmed != 1) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintpositionen $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, markiere # diese Lesart als nicht zu verwerfen, ansonsten behalte sie bei if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $contradiction != 1) { $discard = 0; $confirmed = 1; } else { $discard = 1; $contradiction = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position nicht dem Postulat im Constraint entspricht, # markiere sie als zu verwerfen, ansonsten behalte sie bei if ($constraintString eq $constraintEnvironmentBuffer[1] || $confirmed == 1) { $discard = 0; $confirmed = 1; } else { $discard = 1; } } } } } else { $discard = 1; } } # Falls Lesart am Ende des Prozesses als zu verwerfen markiert ist, loesche sie aus der # entsprechenden Kohorte if ($discard == 1 && scalar (@thisCohortBuffer) > 1 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)), 1); $processed{$k} = 1; } } # Ende DISCARD_THIS_UNLESS Modus # DISCARD_STRICTLY Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus wird die behandelte Lesart verworfen, wenn die Bedingungen # erfuellt sind, sind diese nicht erfuellt, werden alle anderen Lesarten # verworfen, entspricht dem Komplement von =!! if ($mode eq "DISCARD_STRICTLY" && !defined ($processed{$k})) { # Nehme zunaechst an, dass keine Lesart geloescht wird, bei einem Wert von 2 werden alle anderen # Lesarten geloescht $discard = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten entferne die Lesart direkt if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohort der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange keine Lesart als zu entfernen markiert ist if ($discard == 0) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintpositionen $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, markiere # diese Lesart als zu verwerfen, ansonsten behalte sie bei und verwerfe alle anderen if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $discard != 2) { $discard = 1; } else { $discard = 2; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position nicht dem Postulat im Constraint entspricht, # markiere sie als zu verwerfen, ansonsten behalte sie bei und verwerfe alle anderen unless ($constraintString eq $constraintEnvironmentBuffer[1]) { $discard = 1; } else { $discard = 2; } } } } } else { $discard = 1; } } # Falls Lesart am Ende des Prozesses als zu verwerfen markiert ist, loesche sie aus der # entsprechenden Kohorte if ($discard == 1 && scalar (@thisCohortBuffer) > 1 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)), 1); $processed{$k} = 1; } # Falls aller anderen Lesarten am Ende des Prozesses als zu verwerfen markiert sind, loesche sie # aus der entsprechenden Kohorte if ($discard == 2 && scalar (@thisCohortBuffer) > 0 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)) + 1, scalar (@thisCohortBuffer) - 1); splice (@thisCohortBuffer, 0, $k - scalar (keys (%processed))); $processed{$k} = 1; } } # Ende DISCARD_STRICTLY MODUS # DISCARD_STRICTLY_UNLESS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus wird die behandelte Lesart verworfen, wenn die Bedingungen # nicht erfuellt sind, sind diese erfuellt, werden alle anderen Lesarten # verworfen, entspricht =!! if ($mode eq "DISCARD_STRICTLY_UNLESS" && !defined ($processed{$k})) { # Nehme zunaechst an, dass keine Lesart geloescht wird, bei einem Wert von 2 werden alle anderen # Lesarten geloescht $discard = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten entferne die Lesart direkt if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohort der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange keine Lesart als zu entfernen markiert ist if ($discard == 0) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintpositionen $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, # behalte sie bei und verwerfe alle anderen, ansonsten verwerfe diese # Lesart if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $discard != 2) { $discard = 2; } else { $discard = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position dem Postulat im Constraint entspricht, # markiere sie als zu verwerfen, ansonsten behalte sie bei und verwerfe alle anderen unless ($constraintString eq $constraintEnvironmentBuffer[1]) { $discard = 2; } else { $discard = 1; } } } } } else { $discard = 1; } } # Falls Lesart am Ende des Prozesses als zu verwerfen markiert ist, loesche sie aus der # entsprechenden Kohorte if ($discard == 1 && scalar (@thisCohortBuffer) > 0 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)), 1); $processed{$k} = 1; } # Falls alle anderen Lesarten am Ende des Prozesses als zu verwerfen markiert sind, loesche sie # aus der entsprechenden Kohorte if ($discard == 2 && scalar (@thisCohortBuffer) > 1 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)) + 1, scalar (@thisCohortBuffer) - 1); splice (@thisCohortBuffer, 0, $k - scalar (keys (%processed))); $processed{$k} = 1; } } # Ende DISCARD_STRICTLY_UNLESS MODUS # DISCARD_OTHERS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus werden alle anderen als die behandelte Lesart verworfen, # wenn die Bedingungen erfuellt sind, entspricht =! if ($mode eq "DISCARD_OTHERS" && !defined ($processed{$k})) { # Nehme zunaechst an, dass keine Lesart geloescht wird $discard = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten entferne die anderen Lesarten nicht if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohort der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange die Lesarten nicht als zu entfernen markiert sind if ($discard == 0) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintbestandteile $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, markiere # alle anderen Lesarten als zu verwerfen, ansonsten behalte diese bei if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $contradiction != 1) { $discard = 1; } else { $discard = 0; $contradiction = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position dem Postulat im Constraint entspricht, # markiere alle anderen Lesarten als zu verwerfen, ansonsten behalte diese bei if ($constraintString eq $constraintEnvironmentBuffer[1]) { $discard = 1; } else { $discard = 0; } } } } } else { $discard = 0; } } # Falls alle anderen Lesarten am Ende des Prozesses als zu verwerfen markiert ist, loesche # diese aus der entsprechenden Kohorte if ($discard == 1 && scalar (@thisCohortBuffer) > 0 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)) + 1, scalar (@thisCohortBuffer) - 1); splice (@thisCohortBuffer, 0, $k - scalar (keys (%processed))); $processed{$k} = 1; } } # Ende DISCARD_OTHERS Modus # DISCARD_OTHERS_UNLESS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus werden alle anderen als die behandelte Lesart verworfen, # wenn die Bedingungen nicht erfuellt sind, entspricht dem Komplement von =! if ($mode eq "DISCARD_OTHERS_UNLESS" && !defined ($processed{$k})) { # Nehme zunaechst an, dass die Lesarten nicht geloescht werden $discard = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten entferne die anderen Lesarten nicht if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohort der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange die Lesarten nicht als zu entfernen markiert sind if ($confirmed != 1) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintbestandteile $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart nicht entspricht oder eine Wildcard vorliegt, markiere # alle anderen Lesarten als zu verwerfen, ansonsten behalte diese bei if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $contradiction != 1) { $discard = 0; $confirmed = 1; } else { $discard = 1; $contradiction = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position dem Postulat im Constraint nicht entspricht, # markiere alle anderen Lesarten als zu verwerfen, ansonsten behalte diese bei if ($constraintString eq $constraintEnvironmentBuffer[1] || $confirmed == 1) { $discard = 0; $confirmed = 1; } else { $discard = 1; } } } } } else { $discard = 0; } } # Falls alle anderen Lesarten am Ende des Prozesses als zu verwerfen markiert ist, loesche # diese aus der entsprechenden Kohorte if ($discard == 1 && scalar (@thisCohortBuffer) > 0 && defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { splice (@thisCohortBuffer, $k - scalar (keys (%processed)) + 1, scalar (@thisCohortBuffer) - 1); splice (@thisCohortBuffer, 0, $k - scalar (keys (%processed))); $processed{$k} = 1; } } # Ende DISCARD_OTHERS_UNLESS Modus # CHANGE_THIS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus wird die behandelte Lesart geaendert, wenn die Bedingungen # erfuellt sind, dies dient dazu, nachtraeglich syntaktische Funktion, Genus # Numerus etc. hinzuzufuegen if ($mode =~ /CHANGE_THIS\=+/ && !defined ($changed{$k})) { # Trenne den Modus nach '=', um den String zu erhalten, in den die Lesart bei Kongruenz mit Constraint # uberfuehrt werden. @changeInto = split (/\=/, $mode); # Nehme zunaechst an, dass die Lesart nicht geaendert wird $change = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten lasse Lesart unberuehrt if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohort der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange die Lesart nicht als zu aendern markiert ist if ($change == 0) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintbestandteile $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, markiere # diese Lesart als zu aendern, ansonsten lasse sie unberuehrt if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $contradiction != 1) { $change = 1; } else { $change = 0; $contradiction = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position dem Postulat im Constraint entspricht, # markiere sie als zu aendern, ansonsten lasse sie unberuehrt if ($constraintString eq $constraintEnvironmentBuffer[1]) { $change = 1; } else { $change = 0; } } } } } else { $change = 0; } } # Falls die Lesart als zu aendern markiert ist, tue dies entsprechend der Anweisung if ($change == 1) { # Setze die neue Lesart aus dem Wort (Index 0 in $readingInformation) der alten Lesart, # einem '+' und der Anweisung zusammenen $newReading = $tokenReading . "+" . $changeInto[1]; # Setze die gerade ueberpruefte Lesart gleich der neuen Lesart if (defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { $thisCohortBuffer[$k - scalar (keys (%processed))] = $newReading; $changed{$k} = 1; } } } # Ende CHANGE_THIS Modus # CHANGE_THIS_UNLESS Modus, wenn Lesart noch nicht behandelt wurde # In diesem Modus wird die behandelte Lesart geaendert, wenn die Bedingungen # nicht erfuellt sind, dies dient dazu, nachtraeglich syntaktische Funktion, Genus # Numerus etc. hinzuzufuegen if ($mode =~ /CHANGE_THIS_UNLESS\=+/ && !defined ($changed{$k})) { # Trenne den Modus nach '=', um den String zu erhalten, in den die Lesart bei Kongruenz mit Constraint # uberfuehrt werden. @changeInto = split (/\=/, $mode); # Nehme zunaechst an, dass die Lesart nicht geaendert wird $change = 0; # Gehe nun jede einzelne Stelle des Constraints durch foreach $thisConstraintEnvironment (@constraintBuffer) { # Teile jede Stelle nach '/', um Position und Wert zu trennen @constraintEnvironmentBuffer = split (/\//, $thisConstraintEnvironment); # Ueberpruefe nur weiter, falls die Positionsangabe die Satzgrenze nicht # ueberschreitet, ansonsten lasse Lesart unberuehrt if ($j + $constraintEnvironmentBuffer[0] >= 0 && $j + $constraintEnvironmentBuffer[0] <= @thisTokens) { # Selegiere die Kohort der im Constraint angebenen Umgebungsposition entsprechend der verschiedenen Hash-Schluesselvarianten if ($hashMode == 0) { $environmentCohort = $thisCohorts{$tokens[$j + $constraintEnvironmentBuffer[0]]}; } if ($hashMode == 1) { if (defined ($thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]})) { $environmentCohort = $thisCohorts{$i . "." . $j + $constraintEnvironmentBuffer[0]}; } else { $environmentCohort = (); } } # Gehe nun jede Lesart an dieser Position durch foreach $environmentReading (@{$environmentCohort}) { # Siehe ### 1 ### @environmentReadingInformation = split (/\+/, $environmentReading); $tokenEnvironmentReading = shift (@environmentReadingInformation); $constraintString = ""; foreach $thisReadingInformation (@environmentReadingInformation) { $constraintString .= $thisReadingInformation . "+"; } $constraintString =~ s/(.*)(\+)$/$1/g; # Solange die Lesart nicht als zu aendern markiert ist if ($confirmed != 1) { # Behandlung von Wildcards und normalen Faellen if ($constraintEnvironmentBuffer[1] =~ /\*/) { # Teile den Constraint in seine Bestandteile auf @constraintParts = split (/\+/, $constraintEnvironmentBuffer[1]); # Definiere Zaehler fuer einzelne Constraintbestandteile $constraintPartCounter = 0; # Setze den Widerspruchswert zurueck $contradiction = 0; # Gehe jeden einzelnen Constraint-Bestandteil durch foreach my $thisConstraintPart (@constraintParts) { # Wenn Constraint an dieser Stelle der Lesart entspricht oder eine Wildcard vorliegt, markiere # diese Lesart als zu aendern, ansonsten lasse sie unberuehrt if (defined ($environmentReadingInformation[$constraintPartCounter])) { if (($thisConstraintPart eq $environmentReadingInformation[$constraintPartCounter] || $thisConstraintPart eq '*') && $contradiction != 1) { $change = 0; $confirmed = 1; } else { $change = 1; $contradiction = 1; } } # Naechste Constraintposition $constraintPartCounter++; } } else { # Wenn die Lesart an dieser Position nicht dem Postulat im Constraint entspricht, # markiere sie als zu aendern, ansonsten lasse sie unberuehrt if ($constraintString eq $constraintEnvironmentBuffer[1] || $confirmed == 1) { $change = 0; $confirmed = 1; } else { $change = 1; } } } } } else { $change = 0; } } # Falls die Lesart als zu aendern markiert ist, tue dies entsprechend der Anweisung if ($change == 1) { # Setze die neue Lesart aus dem Wort (Index 0 in $readingInformation) der alten Lesart, # einem '+' und der Anweisung zusammenen $newReading = $readingInformation[0] . "+" . $changeInto[1]; # Setze die gerade ueberpruefte Lesart gleich der neuen Lesart if (defined (@thisCohortBuffer[$k - scalar (keys (%processed))])) { $thisCohortBuffer[$k - scalar (keys (%processed))] = $newReading; $changed{$k} = 1; } } } # Ende CHANGE_THIS_UNLESS Modus # Ende Modus-Switch } # Ende Iteration ueber Constraints } # Ende Abfrage, ob Constraints existieren # Zaehle Pointer fuer Kohorte hoch $k++; } # Ende Iteration ueber Lesarten # Die disambiguierten Kohorten werden in eine neue Datenstruktur geschrieben, Schluessel # ist dabei die Satznummer und die Wortnummer in dem jeweiligen Satz $disambiguatedCohorts{$i . "." . $j} = \@thisCohortBuffer; # Zaehle Tokenzaehler im jeweiligen Satz hoch $j++; } # Ende Abfrage, ob Kohorte zu Wort existiert } # Ende Iteration ueber Token # Zaehle Satzzaehler hoch $i++; } # Ende Iteration ueber Saetze # Disambiguierte Kohorten speichern saveDisambiguatedCohorts (\%disambiguatedCohorts); # Disambiguierte Kohorten zurueckgeben return \%disambiguatedCohorts; } # Ende der Funktion zum Disambiguieren # Funktion zum Einlesen der Constraints sub readConstraints { # Puffer fuer Constraints my %constraints; # Ordner mit Constraints oeffnen opendir (DIR, "constraints/"); # Iteriere ueber alle Constraintdateien, diese haben die Namenskonvention # 'TAG.txt', wobei 'TAG', sowohl fuer einfache ('NP'), als auch # komplexe ('NP+3SG+AKK') Ausdruecke stehen kann while (my $constraintFile = readdir (DIR)) { # Oeffne die Datei (falls sie nicht mit einem Punkt beginnt, i.e eine OS-interne # Funktion hat) mit den Constraints fuer dieses Tag unless ($constraintFile =~ /^\./ || $constraintFile =~ /.*\~.*/) { # Oeffne Datei open (CONSTRAINTS, "constraints/" . $constraintFile); # Schreibe die Constraints fuer dieses Tag der Prioritaet nach in ein Array my @thisConstraintCollection; while (my $thisConstraint = ) { # Entferne Zeilenenden chomp $thisConstraint; # Schreibe Zeile in Array, wenn diese nicht leer ist unless ($thisConstraint eq '') { push (@thisConstraintCollection, $thisConstraint); } } # Schreibe dieses Array in einen Hash mit allen Constraints, mit den Tag- # bezeichnungen (ohne '.txt') als Schluessel $constraintFile =~ s/\.txt//g; $constraints{$constraintFile} = \@thisConstraintCollection; # Schliesse Datei close (CONSTRAINTS); } } # Schliesse Verzeichnis closedir (DIR); # Gebe die Constraints zurueck return \%constraints; } # Ende der Funktion zum Einlesen der Constraints # Funktion zum Aufteilen der Tokens in einzelne Saetze, veraltet, # wird nun mittels $tokenizer->extract_sentences durchgefuehrt sub readSentences { # Puffer fuer einen einzelnen Satz my $sentenceBuffer; # Puffer fuer Saetze, die zurueckgegeben werden my @sentences; # Alle Token eines Corpus my @thisTokens; # Dereferenzieren des Token-Arrays auf das lokale Array @thisTokens = @{$_[0]}; # Initialisieren des Zwischenspeichers fuer einzelne Saetze $sentenceBuffer = ""; # Iteriere ueber alle Tokens eines Corpus foreach my $thisToken (@thisTokens) { # Solange kein Satzende auftritt, fuege Token an den Satzpuffer an, # ansonsten fuege Satzendezeichen an, werfe Puffer auf den Stack # und leere den Puffer fuer einzelne Saetze unless ($thisToken eq '.') { $sentenceBuffer .= $thisToken . " "; } else { $sentenceBuffer .= $thisToken; chomp $sentenceBuffer; push (@sentences, $sentenceBuffer); $sentenceBuffer = ""; } } # Gebe Stack mit Saetzen zurueck return \@sentences; } # Ende der Funktion zum Aufteilen der Tokens in einzelne Saetze # Funktion zum Anzeigen von Kohorten sub displayCohorts { # Hash fuer alle Kohorten my %thisCohorts; # Zwischenspeicher fuer aufgeteilte Kohortenzeilen my @thisCohortLine; # Zwischenspeicher fuer Saetze eines Corpus my @thisSentences; # Zwischenspeicher fuer Tokens eines Satzes my @thisTokens; # Speicher fuer Anzeigemodus (0=mit Worten als Schluesseln, 1=mit Indices als # Schluesseln my $displayMode; # Satzanzahl my $i = 0; # Tokenanzahl my $j = 0; # Dereferenzieren der uebergebenen Argumente %thisCohorts = %{$_[0]}; @thisSentences = @{$_[1]}; $displayMode = $_[2]; # Trennzeichen ausgeben print "------------------------------------------------------\n"; # Iteriere ueber alle Saetze foreach my $thisSentence (@thisSentences) { # Trennzeichen ausgeben print "-------------------- Neuer Satz-----------------------\n"; # Setze Tokenpointer auf 0; $j = 0; # Teile nach Tokens @thisTokens = split (/ /, $thisSentence); # Iteriere ueber Tokens foreach my $thisToken (@thisTokens) { # Ausgabe des Wortes print "$thisToken:\n\n"; # Falls Worte als Schluessel der Kohorten uebergeben wurden if ($displayMode == 0) { # Iteriere ueber Zeilen einzelner Kohoerten foreach my $thisCohortLine (@{$thisCohorts{$thisToken}}) { # Zeile nach '+' aufteilen @thisCohortLine = split (/\+/, $thisCohortLine); # Entferne Wort aus der Zeile shift (@thisCohortLine); # Gebe Zeile aus print "\t\t\t@thisCohortLine\n"; } } # Falls Indices als Schluessel der Kohorten uebergeben wurden if ($displayMode == 1) { # Iteriere ueber Zeilen einzelner Kohoerten foreach my $thisCohortLine (@{$thisCohorts{$i . "." . $j}}) { # Zeile nach '+' aufteilen @thisCohortLine = split (/\+/, $thisCohortLine); # Entferne Wort aus der Zeile shift (@thisCohortLine); # Gebe Zeile aus print "\t\t\t@thisCohortLine\n"; } } # Trennzeichen ausgeben print "------------------------------------------------------\n"; # Tokenzaehler erhoehen $j++; } # Satzzaehler erhoehen $i++; } } # Ende der Funktion zum Anzeigen von Kohorten # Funktion zum Anzeigen von nicht disambiguierten und disambiguierten Kohorten # in Tabellenform sub displayCohortsInTable { # Hash fuer alle nicht disambiguierten Kohorten my %thisCohorts; # Hash fuer alle disambiguierten Kohorten my %thisDisambiguatedCohorts; # Zwischenspeicher fuer aufgeteilte Kohortenzeilen my @thisCohortLine; my @thisDisambiguatedCohortLine; # Zwischenspeicher fuer Saetze eines Corpus my @thisSentences; # Zwischenspeicher fuer Tokens eines Satzes my @thisTokens; # Speicher fuer Anzeigemodus (0=mit Worten als Schluesseln, 1=mit Indices als # Schluesseln my $displayMode; # Satzanzahl my $i = 0; # Tokenanzahl my $j = 0; # Zaehler fuer Kohortenzeilen my $cohortLineCounter = 0; # Tabulatoren my $tabs; # Dereferenzieren der uebergebenen Argumente %thisCohorts = %{$_[0]}; %thisDisambiguatedCohorts = %{$_[1]}; @thisSentences = @{$_[2]}; # Trennzeichen ausgeben print "-------------------------------------------------------------------------------\n"; # Iteriere ueber alle Saetze foreach my $thisSentence (@thisSentences) { # Trennzeichen ausgeben print "-------------------- Neuer Satz------------------------------------------------\n"; # Setze Tokenpointer auf 0; $j = 0; # Teile nach Tokens @thisTokens = split (/ /, $thisSentence); # Iteriere ueber Tokens foreach my $thisToken (@thisTokens) { # Setze Zaehler fuer Kohortenzeilen auf 0 $cohortLineCounter = 0; # Ausgabe des Wortes, if (length ($thisToken) < 7) { $tabs = "\t\t"; } else { $tabs = "\t"; } print "$thisToken:" . $tabs . "Nicht disambiguiert\tdisambiguiert\n\n"; # Iteriere ueber Zeilen einzelner nicht disambiguierter Kohoerten foreach my $thisCohortLine (@{$thisCohorts{$thisToken}}) { # Zeile nach '+' aufteilen @thisCohortLine = split (/\+/, $thisCohortLine); # Entferne Wort aus der Zeile shift (@thisCohortLine); # Falls noch eine Zeile in der entsprechenden disambiguierten Kohorte # vorhanden ist, wiederhole den Prozess fuer diese, ansonsten # definiere das Array als leer if (defined (@{$thisDisambiguatedCohorts{$i . "." . $j}}[$cohortLineCounter])) { # Zeile nach '+' aufteilen @thisDisambiguatedCohortLine = split (/\+/, @{$thisDisambiguatedCohorts{$i . "." . $j}}[$cohortLineCounter]); # Entferne Wort aus der Zeile shift (@thisDisambiguatedCohortLine); } else { @thisDisambiguatedCohortLine = (); } # Gebe Zeile aus print "\t\t@thisCohortLine\t\t@thisDisambiguatedCohortLine\n"; # Erhoehe Zaehler fuer Kohortenzeilen um 1 $cohortLineCounter++; } # Trennzeichen ausgeben print "-------------------------------------------------------------------------------\n"; # Tokenzaehler erhoehen $j++; } # Satzzaehler erhoehen $i++; } } # Ende der Funktion zum Anzeigen von nicht disambiguierten und # disambiguierten Kohorten in Tabellenform # Funktion zum Laden der disambiguierten Kohorten sub loadDisambiguatedCohorts { # Hash fuer disambiguierte Kohorten my %thisDisambiguatedCohorts; # Array fuer einzelne Zeilen einer Kohorte; my @thisCohort; # Oeffne Datei zum Lesen der Kohorten open (DC, "disambiguated-cohorts.txt") or die "$!\n"; # Iteriere ueber Datei while (my $line = ) { # Teile nach Wortindex und der dazugehoerigen Kohorte auf chomp $line; my @cohortBuffer = split (/\:/, $line); # Teile nach den einzelnen Zeilen der Kohorte auf my @cohortLinesBuffer = split (/\;/, $cohortBuffer[1]); # Speichere die Kohorte im Hash unless ($line eq '') { $thisDisambiguatedCohorts{$cohortBuffer[0]} = \@cohortLinesBuffer; } } # Schliesse Datei close (DC); # Gebe disambiguierte Cohorten zurueck return \%thisDisambiguatedCohorts; } # Ende der Funktion zum Laden der disambiguierten Kohorten # Funktion zum Speichern der disambiguierten Kohorten sub saveDisambiguatedCohorts { # Hash fuer disambiguierte Kohorten my %thisDisambiguatedCohorts; # Dereferenzieren auf lokalen Hash %thisDisambiguatedCohorts = %{$_[0]}; # Oeffne Datei zum Speichern der Kohorten open (DC, ">disambiguated-cohorts.txt") or die "$!\n"; # Iteriere ueber alle Kohorten foreach my $thisDisambiguatedCohortsKey (keys (%thisDisambiguatedCohorts)) { # Dereferenziere Kohorte auf lokalen Wert my @thisCohort = @{$thisDisambiguatedCohorts{$thisDisambiguatedCohortsKey}}; # Schreibe Wortindex an den Zeilenanfang, abgetrennt von den # Kohortenzeilen durch ':' print DC "$thisDisambiguatedCohortsKey:"; # Schreibe dahinter jede Kohortenzeile, getrennt jeweils mit ';' foreach my $thisCohortLine (@thisCohort) { print DC "$thisCohortLine;"; } # Schreibe Zeilenumbruch, i.e. der naechste bitte! print DC "\n"; } # Schliesse Datei close (DC); } # Ende der Funktion zum Speichern der disambiguierten Kohorten ### Ende Funktionsdefinition ### Anfang Praeliminarien, Preprocessing # Programmstart print "\n### Start ###\n"; # Bildschirm leeren system ("clear"); # Corpus-Datei oeffnen open (FH, $corpusFile) or die "$!\n"; # Datei 'schluerfen' undef ($/); $wholeCorpus = ; $/ = "\n"; # Datei schliessen close (FH); # Tokenisieren und normalisieren $tokenizer = new Lingua::Tokenize ({debug=>1}); @tokens = $tokenizer->tokenize ({tokendef=>'words', normalize=>1, input=>\$wholeCorpus}); @sentencesToBeDisambiguated = $tokenizer->extract_sentences (\@tokens); @types = $tokenizer->unify (\@tokens); ### Ende Praeliminarien, Preprocessing ### Anfang morphologische Analyse # Morphologische Analyse, siehe 'perldoc XFST::Lookup' $lookup = new XFST::Lookup ({debug=>1, path=>$xfstPath}); $lookup->set_flags("mb"); %cohorts = $lookup->lookup ({strategy=>'./strategy.txt', words=>\@types}); # Ausgabe der nicht disambiguierten Analyse, auskommentiert, Ausgabe erfolgt # nun komplett am Programmende # print "Eingabe: \n\n"; # displayCohorts (\%cohorts, \@sentencesToBeDisambiguated, 0); ### Ende morphologische Analyse ### Anfang Disambiguierung # Einlesen der einzelnen Saetze des Corpus, wird nun mittels $tokenizer->tokenize durchgefuehrt # @sentencesToBeDisambiguated = @{readSentences (\@tokens)}; # Zwischenspeicher-Datei fuer disambiguierte Kohorten verschieben rename ("disambiguated-cohorts.txt", "disambiguated-cohorts-" . time () . ".txt"); # Startzeitpunkt der Disambiguierung holen $startTime = time (); # Erster Durchlauf ohne bereits teilweise disambiguierte Kohorten %disambiguatedCohorts = %{disambiguate (\@sentencesToBeDisambiguated, \%cohorts, 0)}; # Weitere Durchlaeufe mit teilweise disambiguierten Kohorten for (my $thisIterations = 1; $thisIterations <= $disambiguationIterations; $thisIterations++) { # Disambiguiere nochmals mit bereits teilweise disambiguierten Kohorten %disambiguatedCohorts = %{disambiguate (\@sentencesToBeDisambiguated, \%disambiguatedCohorts, 1)}; } # Endzeitpunkt der Disambiguierung holen $endTime = time (); # Ausgabe der Analyse displayCohortsInTable (\%cohorts, \%disambiguatedCohorts, \@sentencesToBeDisambiguated); # Ausgabe der zum Disambiguieren benoetigten Laufzeit $runTime = $endTime - $startTime; if ($runTime <= 0) { $runTime = 1; } # Ausgabe mit 'Sekunden' oder 'Sekunde' if ($runTime == 1) { $plural = ""; } else { $plural = "n"; } # Ausgabe print "\n\nLaufzeit beim Disambiguieren: $runTime Sekunde$plural bei " . scalar (@tokens) . " Token (" . @tokens / $runTime . " Token pro Sekunde)\n"; # Programmende print "\n### Ende ###\n"; ### Ende Disambiguierung