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 37 38
use strict; use warnings; use Data::Dumper qw(Dumper); my ($datei, @zeilen, %hash); $datei = 'test.txt'; sub reg_exe { $_ = lc($_); $_ =~ s/\W+|\d|_/ /g; $_ =~ s/^\s+|\s+$//; } # Datei wird zeilenweise ausgelesen und in Array geschrieben # (pro Index eine Zeile) open(DATEI, "<$datei") || die "$datei kann nicht geoeffnet werden: $!"; @zeilen = <DATEI>; foreach(@zeilen) { reg_exe(); } print Dumper \@zeilen; # Datei wird zeilenweise ausgelesen --> in Wörter gesplittet, # in Hash abgelegt und Anzahl der Häufigkeit ermittelt open(DATEI, "<$datei") || die; while (<DATEI>){ foreach(split(/ /, $_)) { reg_exe(); $hash{$_}++; } } print Dumper \%hash; # Ausgabe AoH # ... close(DATEI);
Quoteür jede Zeile der Eingabedatei einen Eintrag enthält, der wiederum aus einem Hash besteht.
Quotesondern aus einer Datei soll ein Array erzeugt werden, dass für jede Zeile einen Hash enthält.
1 2 3 4 5 6 7
my %eav; # Hahsh of Hashes foreach my $line( <FILEHANDLE>){ chomp $line; my ($ent, $att, $val) = split /\./, $line; $eav{$ent}{$att} = $val; } print Dumper \%eav;
1
2
3
4
5
6
7
8
$VAR1 = {
'addr' => {
'name' => 'Nonsens',
'ort' => 'Irgendwo',
'plz' => '12345',
'vname' => 'Oliver'
}
};
2020-02-04T16:36:53 RaubtierDein EAV mag ja schön und gut sein, aber mir erschließt sich der Zusammenhang zur Frage / zum Thema überhaupt nicht.
1 2 3 4 5 6 7 8 9 10 11 12 13
foreach ( <DATA>){ chomp; my @row = split; my %h = @row; push @data, \%h; } print Dumper \@data; __DATA__ name Nonsens vname Oliver ort Irgendwo name Hansel vname Ulrich ort Adorf name Pfotenhauer vname Fritz ort BB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$VAR1 = [
{
'name' => 'Nonsens',
'ort' => 'Irgendwo',
'vname' => 'Oliver'
},
{
'name' => 'Hansel',
'ort' => 'Adorf',
'vname' => 'Ulrich'
},
{
'name' => 'Pfotenhauer',
'ort' => 'BB',
'vname' => 'Fritz'
}
];
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
use strict; use warnings; use Data::Dumper qw(Dumper); my ($datei, @zeilen, %hash); $datei = 'test.txt'; #XXX Deklariere&definiere die Variablen erst dann, wenn du sie brauchst. #XXX also my $datei = 'test.txt' #XXX Was ist das für ein Funktionsname? Was hat diese Funktion für Argumente? #XXX Hint: Argumente sind in @_ sub reg_exe { $_ = lc($_); $_ =~ s/\W+|\d|_/ /g; $_ =~ s/^\s+|\s+$//; } # Datei wird zeilenweise ausgelesen und in Array geschrieben # (pro Index eine Zeile) #XXX NEIN, du liest nicht zeilenweise, sondern alles auf einmal open(DATEI, "<$datei") || die "$datei kann nicht geoeffnet werden: $!"; #XXX Nutze bitte keine globalen Dateihandles! Und nimm die 3-argument-Form von open. #XXX Also: #XXX open my $inputFH, '<', $datei or die ... @zeilen = <DATEI>; #XXX Das hier ist alles auf einmal, nicht zeilenweise foreach(@zeilen) { reg_exe(); } print Dumper \@zeilen; # Datei wird zeilenweise ausgelesen --> in Wörter gesplittet, # in Hash abgelegt und Anzahl der Häufigkeit ermittelt open(DATEI, "<$datei") || die; #XXX again, kein globales Dateihandle DATEI verwenden, sondern eine normale #XXX lokale Variable dafür nehmen! while (<DATEI>){ #XXX benennen schadet nicht. $_ ist toll für Einzeiler, aber nicht für Loops mit mehr als 1 Zeile! #XXX while (my $line = <$inputFH>) { foreach(split(/ /, $_)) { #XXX Auch hier benennen! #XXX for my $word (split(/ /, $line)) { #XXX mach was mit $word reg_exe(); $hash{$_}++; } } print Dumper \%hash; # Ausgabe AoH # ... close(DATEI);
QuoteDurch Data::Dumper weiß ich, dass in meinem erzeugten Array tatsächlich pro Index eine Zeile der Textdatei enthalten ist und dass mein Hash in der Lage ist, Wörter und Häufigkeit aufzuschlüsseln. Leider ist es mir nicht gelungen, beides zu kombinieren. Bisherige Recherchen haben mich auch nicht weitergebracht. Ich hoffe, ihr könnt mir helfen, da ich ein blutiger Anfänger bin.
1 2 3 4 5 6 7 8
my @output; while (my $line = <$inputFH>) { my %wordCounter; for my $word (splitLine($line)) { # splitLine muss du machen ++$wordCounter{$word}; } push @output, \%wordCounter; }
QuoteCode: (dl )1
2
3
4
5
6
7
8my @output;
while (my $line = <$inputFH>) {
my %wordCounter;
for my $word (splitLine($line)) { # splitLine muss du machen
++$wordCounter{$word};
}
push @output, \%wordCounter;
}
for my $word (split(/ /, $line)) {
1 2 3 4 5
for my $zeile ( @zeilen ) { my %hash; # splitte und fuelle Hash # Ersetze dann den Wert von $zeile mit einer Referenz auf den Hash }
2020-02-04T14:59:30 Linuxer
QuoteCode (perl): (dl )# Ersetze dann den Wert von $zeile mit einer Referenz auf den Hash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
my @names = (); my @fields = split /\s+/, <DATA>; # Ziehe die Feldnamen foreach ( <DATA>){ chomp; my %hunt = (); @hunt{@fields} = split; # Hash Slice push @names, \%hunt; } print Dumper \@names; __DATA__ Name Vorname Ort Nonsens Oliver Irgendwo Hansel Ulrich Adorf Pfotenhauer Fritz BB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$VAR1 = [ { 'Name' => 'Nonsens', 'Ort' => 'Irgendwo', 'Vorname' => 'Oliver' }, { 'Name' => 'Hansel', 'Ort' => 'Adorf', 'Vorname' => 'Ulrich' }, { 'Name' => 'Pfotenhauer', 'Ort' => 'BB', 'Vorname' => 'Fritz' } ];
2020-02-04T10:19:41 Flips87ich habe folgende Aufgabenstellung
Flips87Dazu der momentane Stand meines Skripts:
2020-02-04T18:44:15 hlubenowDas Blöde ist, daß in Perl das Array nicht einfach die Hashes selbst halten kann, sondern nur Referenzen auf Hashes.
Python dagegen kann in Arrays ("Listen") die Hashes (dort: "Dictionaries") selbst halten, so daß man keine Referenzen braucht ... und auch später nichts dereferenzieren muß oder so
2020-02-05T06:34:03 rostiReferenzen sind nicht blöd. Ganz im Gegeteil: Referenzen sind Clever. Gerade wenn man sehr große Datenmengen hat, wird man diese per Referenz übergeben damit man die Daten nicht doppelt im Hauptspeicher hat.
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
use strict; use warnings; use Data::Dumper qw(Dumper); sub nurKleinbuchstaben{ my $string = shift(@_); $string = lc($string); $string =~ s/\W+|\d|_/ /g; $string =~ s/^\s+|\s+$//; } my $datei = 'test.txt'; open(my $inputFH, '<', $datei) or die "Fehler: $!"; my @zeilen = $inputFH; foreach (@zeilen) { nurKleinbuchstaben($_); } for my $zeile (@zeilen) { my %wordCounter; for my $word (split(/ /, $zeile)) { ++$wordCounter{$word}; } # $zeile mit Referenz auf den Hash ersetzen } close($inputFH);
$hash{"wort"} = $count;
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 37 38 39 40 41 42 43 44 45 46 47 48 49
#!/usr/bin/perl use warnings; use strict; use Data::Dumper; my $datei = 'test.txt'; sub prepareLine { my $line = shift; chomp($line); $line = lc($line); $line =~ s/\W+|\d|_/ /g; $line =~ s/^\s+|\s+$//; return $line; } sub getCount { my $str = shift; my @arr = @_; my $count = 0; for my $i (@arr) { if ($i eq $str) { $count++; } } return $count; } my $fh; open($fh, "<", $datei); my @zeilen; my $line; my $i; my $count; while ($line = <$fh>) { $line = prepareLine($line); my @splitted = split(/ /, $line); my %hash; for $i (@splitted) { $count = getCount($i, @splitted); $hash{$i} = $count; } push(@zeilen, \%hash); } close($fh); print Dumper(\@zeilen);
2020-02-05T09:01:22 Flips87Wow, der Code funktioniert einwandfrei. Tausend Dank :) Da hätte ich tatsächlich noch eine Weile daran gesessen.
2020-02-05T09:01:22 Flips87Welchen Unterschied macht es eigentlich wenn man das "++" in Zeile 25 vor "$count" stellen würde? So wie es Raubtier vorgeschlagen hat?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#!/usr/bin/perl use warnings; use strict; my $a = 5; print "$a\n"; my $b = $a++; print "$b\n"; $a = 5; print "$a\n"; my $c = ++$a; print "$c\n";
QuoteGern. Aber versuch' bitte trotzdem, das eine oder andere daraus zu verstehen, wenn das möglich ist. Durch so eine Aufgabe sollst Du ja was lernen.
QuoteBei "++$a" wird also erst erhöht und dann der Variablen $c zugewiesen.
Ich persönlich verwende den "++"-Operator aber nie so, sondern immer nur einfach "$a++;" als Ersatz für die Anweisung "$a = $a + 1;".
$a = $a +1
$a += $a
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 37 38 39 40 41 42 43 44 45 46 47
use strict; use Data::Dumper; my $filename = 'test.txt'; # hier musst du angeben, wie deine Datei kodiert ist # unter Windows wahrscheinlich Windows-1252 statt utf-8 # die Angabe ist wichtig, damit Umlaute von der Regex # als Buchstaben erkannt werden. open my $inputFH, '<:encoding(utf8)', $filename or die $!; # hier gibst du an, in welcher Kodierung deine Ausgabe auf # die Konsole stattfinden soll. Achtung: dadurch werden Umlaute # von Data::Dumper trotzdem nicht angezeigt, wohl aber in # "printResult" unten. binmode STDOUT, ':utf8'; my @output; while (my $line = <$inputFH>) { my %wordCounter; for my $word (splitLineIntoWords($line)) { ++$wordCounter{$word}; } push @output, \%wordCounter; } printResult(\@output); # gibt auch Umlaute korrekt aus print Dumper \@output; sub splitLineIntoWords { my $line = shift; $line = lc($line); # Kleinbuchstaben - wäre zu debattieren, ob das im Sinne der Aufgabe ist $line =~ s/[^[:alpha:]]/ /g; # Alle Nicht-Buchstaben durch spaces ersetzen return split ' ', $line; # Spezialfall ' ': Whitespace-Split } sub printResult { my $outputLinesRef = shift; my $line = 1; for my $oline (@$outputLinesRef) { while (my ($k, $v) = each %$oline) { print "Zeile $line: Wort $k kommt ${v}x vor.\n"; } ++$line; } }
2020-02-05T11:58:33 RaubtierCode (perl): (dl )1 2 3 4 5 6sub splitLineIntoWords { my $line = shift; $line = lc($line); # Kleinbuchstaben - wäre zu debattieren, ob das im Sinne der Aufgabe ist $line =~ s/[^[:alpha:]]/ /g; # Alle Nicht-Buchstaben durch spaces ersetzen return split ' ', $line; # Spezialfall ' ': Whitespace-Split }
1 2 3 4 5
sub splitLineIntoWords { my $line = fc shift; no warnings "experimental::regex_sets"; $line =~ /(?[ \w - \d - [_] ])+/g; }
2020-02-05T14:57:19 hajDie POSIX-Klasse [:alpha:] unterscheidet sich von Perls \w dadurch, dass der Unterstrich '_'nicht drin ist. Im normalen Sprachgebrauch gehört der Unterstrich zu den Sonderzeichen, und die ursprüngliche Lösung von Flips87 behandelt ihn auch so. Andererseits erwischt \w auch Buchstaben wie das "ö", das durchaus Bestandteil von Wörtern sein kann, aber es ist eben nicht in [:alpha:] enthalten. Ein s/[^[:alpha:]]/ /g; macht aus 'Wörtern' dann 'W rtern'.
1
2
$ echo hallöle | perl -nE 'BEGIN{binmode STDIN, ":utf8"} say "ok" if /hall[[:alpha:]]le/'
ok
QuoteDas \w erfasst auch Zahlen. In der Original-Regex werden aus "3,1415" zwei Wörter "3" und "1415". Das kann Flips87 vermutlich beantworten, ob das so sein soll, wahrscheinlich ist es einfach unwichtig.
for my $word ($line =~ m/([[:alpha:]]+)/g) {
2020-02-05T11:58:33 RaubtierIch frage mich, was du (hlubenow) da kompliziertes mit dem getCount erreichen willst.
++$wordCounter{$word};
RaubtierAußerdem hast du extrem viele globale Variablen (schlecht!)
2020-02-05T19:23:49 hlubenow
QuoteUnd das auch noch mit dem "++" davor, obwohl der Ausdruck gar nicht zugewiesen oder ausgewertet wird.
QuoteRaubtierAußerdem hast du extrem viele globale Variablen (schlecht!)
Och, bei so einem kurzen Skript fällt das, glaube ich, nicht weiter ins Gewicht. Ich nehm' mir halt so viele Variablen, wie ich möchte. Dann kann man auch später leichter nachvollziehen, was da vor sich ging.
1 2 3 4 5 6
my $x; # erzeuge Variable $x mit Wert undefined for $x (@liste) { # loope mit $x über die Liste ... } # hier ist $x immer noch gültig. Was für einen Wert hat es (war # vielleicht ein last in der loop)? Wofür brauchst du hier noch das $x?
1 2 3 4 5
for my $x (@liste) { # loope mit $x über die Liste # $x ist nur hier im Loop-Body gültig. ... } # $x nicht mehr da. Du brauchst die keine Gedanken mehr über $x zu machen
QuoteAber klar, ich bin nur ein Hobby-Programmierer, der Perl (und auch Python) eher so schreibt, wie Anfänger es tun würden.
QuoteDas auch absichtlich, wegen der Lesbarkeit.
1 2 3 4 5 6 7
use List::Util qw(sum); my @words = qw(hallo du hallo sonstwer); my $anzahlHallo = sum map {$_ eq "hallo"} @words; # oder auch use List::MoreUtils qw(true); # hier hätte ich n_true o.ä. besser gefunden als Namen my $anzahlHallo = true {$_ eq "hallo"} @words;
QuoteAber gerade bei solchen Aufgaben findet der Lehrer es bestimmt nicht schlecht, wenn man nicht alles verkürzt oder im Extremfall einen Code hat, der z.B. nur noch aus RegExes und map()-Zeilen besteht.
1 2 3 4 5 6 7 8 9
while ($line = <$fh>) { $line = prepareLine($line); my @splitted = split(/ /, $line); my %hash; for $i (@splitted) { $hash{$i} += 1; } push(@zeilen, \%hash); }
1 2 3 4
my $zeile = ":word, text,asdf; foo.bar"; my $words = [ $zeile =~ /\w+/g ]; print Dumper $words;
2020-02-05T08:15:59 Flips87Code (perl): (dl )1 2 3 4 5 6 7foreach (@zeilen) { nurKleinbuchstaben($_); } for my $zeile (@zeilen) { .... }
$cnt{$word}++
$cnt{$.}{$word}
Quote... für jede Zeile der Eingabedatei einen Eintrag enthält, der wiederum aus einem Hash besteht. In diesem Hash sind die einzelnen Worte der Zeile und deren Häufigkeit abzulegen.
eins zwei eins drei fünf zwei drei zwei
2020-02-05T09:06:52 DaximErzähl keinen Quatsch. https://de.wikipedia.org/wiki/H%C3%A4ufigkeit
Mal generell: warum hast du eigentlich keine Hemmungen, irgendeinen Schwachsinn ins Web zu schreiben und Neulinge zu verunsichern? Es nervt. Ich verlange, dass du ein Mindestmaß an Qualität und Dekorum an den Tag legst, so wie wir anderen Stammpfostierer es auch tun.