Schrift
[thread]12087[/thread]

Textnormalisierung...Hilfe! (Seite 2)



<< |< 1 2 >| >> 19 Einträge, 2 Seiten
Linuxer
 2008-06-26 19:25
#111567 #111567
User since
2006-01-27
3872 Artikel
HausmeisterIn

user image
perlre - Look-Around Assertions

Und der Modifier /e ist hier hilfreich.

Du kannst den Regex nach Wörtern suchen lassen, die auf einen Punkt folgen und dann den Treffer an eine Subroutine geben, die die Kontrolle gegen den Index macht und entweder das originale Wort zurückliefert oder eben die kleingeschriebene Variante.
Dazu brauchst Du den Modifier /e


Schema (ungetestet):
Code (perl): (dl )
1
2
3
4
5
6
7
8
$text =~ s/ (?<=\.\x20) (\w+) /foo($1)/xeg;

sub foo {
  my $word = shift;
  my $lc_word = lc $word;
  return $word if not exists $hash{ $lc_word };
  return $lc_word;
}
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
moritz
 2008-06-26 19:31
#111568 #111568
User since
2007-05-11
923 Artikel
HausmeisterIn
[Homepage]
user image
Gast+2008-06-26 17:17:34--
Wenn ein bestimmtes Wort innerhalb eines Satzes (also nicht am Satzanfang) immer kleingeschrieben wird, und es taucht plötzlich am Satzanfang auf, ist aber da großgeschrieben, dann soll Perl dieses Wort am Satzanfang in Kleinbuchstaben umwandeln. So benötigt man keinerlei sprachliches Wissen.

...

Zunächst könnte man doch alle verschiedenen kleingeschriebenen Wörter im Text in einem Hash ablegen, in etwa so:

...

Jetzt möchte ich nur alle Wörter am Satzanfang betrachten, also alle großgeschriebenen Wörter, die nach einem Punkt kommen. Wenn ein solches Wort identisch ist mit einem Wort aus dem Hash und sich nur in der Schreibung unterscheidet, dann soll dieses Wort am Satzanfang eben kleingeschrieben werden. Aber ich weiß nicht, ob sowas a) geht und b) wies geht. Meine Versuche warn bisher erfolglos.


Also ein vielversprechender Ansatze wäre, den Text erst in Tokens zu zerlegen. Ein Token ist in deinem Fall ein Wort oder ein Satzzeichen.

Dann läufst du deine Tokens, und schaust bei jedem Wort, ob es vor einem Satzzeichen oder am Anfang des Strings steht. Wenn das nicht der Fall ist, speicherst du das in einem Hash.

Dann gehst du nochmal durch die Tokens, und ersetzt alles, was du ersetzten willst.

Auf diese Art kannst du was, was in Regexes kompliziert ist (also z.B. Lookaround und andere Art von Kontextsensitivität) vermeiden und es stattdessen in normalem Code machen. Dann brauchst du nur noch Regexes, um den String in Tokens zu zerlegen.
Gast Gast
 2008-06-26 19:35
#111569 #111569
Ein Ansatz der alle Wörter am Satzanfang ersetzt, falls sie öfter klein als großgeschrieben nicht am Satzanfang vorkommen:
[code]#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my $text = 'Hier steht ein langer Text , in dem das erste Wort klein gemacht werden soll , so wie hier .';
print "Input:\n$text\n\n";


my @words = split ' ', $text;

my %words;
my %starting_words = map {
my$t = $words[$_];
$words{$t}--;
$t => $_
} grep {
$words{$words[$_]}++;
$words[$_-1] =~ /^[\.!\?]$/
} 0 .. $#words;

foreach my $key ( keys %starting_words )
{
my $lckey = lcfirst $key;

if ( exists $words{$lckey} && ( $words{$lckey} > $words{$key} ) )
{
$words[$starting_words{$key}] = $lckey;
} # if
} # foreach


print "Output:\n", join( ' ', @words ), "\n";
<STDIN>;

__END__
KurtZ
 2008-06-26 19:39
#111570 #111570
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
also zuerstmal finde ich Threadtitel mit "Hilfe!" kacke aber hier trotzdem mein Senf:

desweieteren hängts von der Regel ab, wenn du sagst

A) alle am Satzanfang großgeschriebenen Wörter die mal kleingeschrieben werden

kannst du es IMHO mit einer einzigen RegEx mit Lookahead schaffen.

Du greifts alle Wörter nach einem Statzendezeichen denen eine kleingeschriebene Version folgt ODER eine kleingeschriebene Version vorhergeht.

Wenn die Regel lautet:

B) alle am Satzanfang großgeschriebenen Wörter die sonst immer und mindestens einmal kleingeschrieben werden!

wirds mit einer RegEx viel schwieriger.

ich würde dann wie Vorgeschlagen eine Schleife mit Parser schreiben, der alle Nichtanfangswörter in ein "Gesehen"-Hash einträgt.

dann im zwoten Durchlauf alle Anfangswörter darauf überprüfen ob in dem gesehen-Hash eine kleingeschriebe Version steht und keine großgeschriebene.

wenn du wilst das dir jetzt hier jmd coden hilft, dann entscheide dich für A oder B oder gib eine neue C vor, RegExe bedeuten nämlich viel Testarbeit und die macht man ungern umsonst.

TMTOWTDYOG (there's more than one way to dig your own grave)
Gast Gast
 2008-06-26 19:50
#111572 #111572
KurtZ+2008-06-26 17:39:46--
also zuerstmal finde ich Threadtitel mit "Hilfe!" kacke aber hier trotzdem mein Senf:

desweieteren hängts von der Regel ab, wenn du sagst

A) alle am Satzanfang großgeschriebenen Wörter die mal kleingeschrieben werden

kannst du es IMHO mit einer einzigen RegEx mit Lookahead schaffen.

Du greifts alle Wörter nach einem Statzendezeichen denen eine kleingeschriebene Version folgt ODER eine kleingeschriebene Version vorhergeht.

Wenn die Regel lautet:

B) alle am Satzanfang großgeschriebenen Wörter die sonst immer und mindestens einmal kleingeschrieben werden!

wirds mit einer RegEx viel schwieriger.

ich würde dann wie Vorgeschlagen eine Schleife mit Parser schreiben, der alle Nichtanfangswörter in ein "Gesehen"-Hash einträgt.

dann im zwoten Durchlauf alle Anfangswörter darauf überprüfen ob in dem gesehen-Hash eine kleingeschriebe Version steht und keine großgeschriebene.

wenn du wilst das dir jetzt hier jmd coden hilft, dann entscheide dich für A oder B oder gib eine neue C vor, RegExe bedeuten nämlich viel Testarbeit und die macht man ungern umsonst.




B) ist richtig. So hab ich das auch gemeint. Halt Wörter, die normalerweise immer kleingeschrieben werden und im Text mitten im Satz auch mindestens einmal kleingeschrieben vorkommen. Sonst würde der Ansatz ja nicht funktionieren.

@Linuxer

Habe grad deinen Ansatz ausprobiert. Das Problem dabei ist, jedes erste Wort eines Satzes wird durch das letzte Wort des gesamten Textes ersetzt. Also jeder Satz beginnt plötzlich immer mit dem gleichen Wort.

Entschuldigt bitte, ich bin noch im ersten Semester und versteh halt alles noch nicht so gut.

@ Gast da oben

Dein Ansatz ist sehr wirr, da steig ich nicht durch. Map- und Grep-Funktion hatten wir noch nicht im Kurs.
Gast Gast
 2008-06-26 19:56
#111573 #111573
@Linuxer

sorry, hab mich vertippt. Dein Ansatz funktioniert perfekt. Nur dumm, dass wir auch Subroutinen im Kurs noch nicht hatten. ^^ Aber den Ansatz versteh ich wenigstens.

Falls jemand aber noch einen Ansatz ohne Subs und nur mit Regex entwickeln kann, wär das sehr nett.
Linuxer
 2008-06-26 19:57
#111574 #111574
User since
2006-01-27
3872 Artikel
HausmeisterIn

user image
Edit: OK. Nachtrag grad gesehen...

Gast+2008-06-26 17:50:56--
@Linuxer

Habe grad deinen Ansatz ausprobiert. Das Problem dabei ist, jedes erste Wort eines Satzes wird durch das letzte Wort des gesamten Textes ersetzt. Also jeder Satz beginnt plötzlich immer mit dem gleichen Wort.


Mein Testskript, was ich auf meinem Vorschlag basierend erstellt habe, liefert mir ein ordentliches Ergebnis, denke ich (Vorher / Nachher ):

Code: (dl )
1
2
Ruhe sanft . Die Ruhe vor dem Sturm . Er ruhe in Frieden . Ruhe ist's, was er sucht . Macht korrumpiert . Das macht aber dem Maechtigen nichts .
ruhe sanft . Die Ruhe vor dem Sturm . Er ruhe in Frieden . ruhe ist's, was er sucht . macht korrumpiert . Das macht aber dem Maechtigen nichts .


meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
KurtZ
 2008-06-26 19:59
#111575 #111575
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
kleine Anmerkungen:

so wie %hash in Beitrag 9 aufgebaut wird werden auch Wörter am Satzanfang eingetragen. M.E. sollten nur solche Wörter normalisiert werden die nie in der Satzmitte groß geschreiben werden, schließlich unterscheidet die Großschreibung manchmal denn Sinn eines Wortes "der Krieg", "ich krieg' mich nicht ein" (ok Umgangssprache aber die Idee wird hoffentlich klar)

Später "Krieg war sein Geschäfft zu normalisieren" obwohl noch ein Satz wie "Verwundet kam er aus dem Krieg" steht wäre IMHO dumm. Dafür muss aber %hash (lieber %gesehen oder besser %mittiges_wort) sauber aufgebaut werden, am besten mit einer analogen RegEx zur späteren Ersetzungs-RegEx.

Desweitern ist der Punkt auch nicht das einzige Satzendezeichen das Großschreibung erzwingt.
TMTOWTDYOG (there's more than one way to dig your own grave)
Gast Gast
 2008-06-26 20:43
#111576 #111576
Gast+2008-06-26 17:50:56--
@ Gast da oben
Dein Ansatz ist sehr wirr, da steig ich nicht durch. Map- und Grep-Funktion hatten wir noch nicht im Kurs.

Hatte auch [/code] vergessen, also nochmal der Code:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/perl

use strict;
use warnings;

my $text = 'Hier steht ein langer Text , in dem das erste Wort klein gemacht werden soll , so wie hier .';
print "Input:\n$text\n\n";


my @words = split ' ', $text;

my %words;
my %starting_words = map {
my $t = $words[$_];
$words{$t}--;
$t => $_
} grep {
$words{$words[$_]}++;
$words[$_-1] =~ /^[\.!\?]$/
} 0 .. $#words;

foreach my $key ( keys %starting_words )
{
my $lckey = lcfirst $key;

if ( exists $words{$lckey} && ( $words{$lckey} > $words{$key} ) )
{
$words[$starting_words{$key}] = $lckey;
} # if
} # foreach


print "Output:\n", join( ' ', @words ), "\n";
<STDIN>;

__END__

Ich hoffe so wirds klarer. Bei dem Input den ich im Code angegeben habe, ist das 'Hier' am Anfang im Output klein.
Es funktioniert folgendermaßen:
Zuerst teile ich den Text in seine Bestandteile auf, indem ich ihn anhand von whitespace split()te.
Schade dass ihr map {} und grep {} noch nicht hattet, aber dieser Teil lässt sich in folgendes umschreiben:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
my %words;
my %starting_words;

for my $i ( 0 .. $#words )
{
my $cur_word = $words[$i];

$words{$cur_word}++;
if ( $words[$i-1] =~ /^[\.!\?]$/ )
{
$words{$cur_word}--;
$starting_words{$cur_word} = $i;
} # if
} # for

Hier speichere ich die Anzahl der Wörter die nicht am Satzanfang stehen. Groß-/Kleinschreibung wird beachtet ('hier' ne 'Hier').
Ausserdem speichere ich alle Wörter die am Satzanfang stehen, mit dazugehörigem Index im Array @words.
Danach durchlaufe ich alle Wörter, die am Satzanfang stehen und überprüfe ob es mehr Wörter im Text (ausser Satzanfänge) gibt, die kleingeschrieben werden. Alle diese Wörter werden dann ersetzt und es folgt die Ausgabe.

MfG
<< |< 1 2 >| >> 19 Einträge, 2 Seiten



View all threads created 2008-06-26 17:45.