Tronde
Anmeldungsdatum: 23. November 2006
Beiträge: 1640
|
Guten Abend. Ich bin neu bei Perl und versuche die Sprache mit Hilfe des Perl5Tutorial von Herbert Breunung erlernen. An der ein oder anderen Stelle bleiben dabei Fragen offen. Ich freue mich, wenn ihr mir diese in diesem Thread beantworten könnt. In Teil 2 wird die Lösung der Aufgabe aus Teil 1 besprochen. Dort findet sich unter anderem der folgende Code: | use v5.12;
use warnings;
use FindBin;
chdir $FindBin::Bin;
open my $FH, '+<', 'notizblock.txt';
say do { local $/; <$FH> };
print "Neue Notiz: ";
my $notiz = <STDIN>;
print $FH $notiz;
|
Im Tutorial steht beschrieben, dass die Zeile | say do { local $/; <$FH> };
|
dafür sorgt, dass <$FH> das Zeilenende nicht erkennt und die Datei bis zum eof einliest. Dies suggeriert mir, dass ohne diesen Block, nur die erste Zeile eingelesen wird. In meinem Programm habe ich diesen Block nicht verwendet. Trotzdem werden alle Einträge aus meiner Datei eingelesen und korrekt ausgegeben. Im Folgenden seht ihr meinen Programmcode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | #!/usr/bin/perl
use v5.18; # Verwende alle neuen Features aus Perl 5.18.
use strict; # Hilft Tippfehler zu finden. ;-)
use warnings; # Gibt ausführlichere Fehlermeldungen aus.
# use diagnostics; # Gibt noch ausführliche Meldungen aus.
use FindBin;
chdir $FindBin::Bin;
my $datei = 'notizblock.txt';
open my $FH, '>>', $datei unless -e $datei;
open $FH, '+<', $datei;
my @notiz = <$FH>;
for my $nr (0 .. $#notiz)
{ print "[$nr]", $notiz[$nr] }
print "Neue Notiz (nur ENTER wenn keine): ";
my $notiz = <STDIN>;
print $FH $notiz if $notiz ne "\n";
close $FH; # File Handle wird geschlossen und die Datei notizblock.txt freigegeben.
|
Könnt ihr mir erklären, warum auch mein Programmcode alle Zeilen einliest? Viele Grüße Tronde
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12821
|
Tronde schrieb:
Könnt ihr mir erklären, warum auch mein Programmcode alle Zeilen einliest?
Du meinst in Zeile 14? Mein Perl ist etwas rostig. (Willst Du nicht lieber Ruby oder Python lernen? 😉) Du verwendest den Dateihandle in einem Array-Kontext, was dazu führt, dass er alle Zeilen in das Array einliest. Der Unterschied zu der anderen Lösung ist, dass Du dort die gesamte Datei in einem String bekommst, während beim Einlesen in das Array natürlich $/ benutzt wird, um die Zeilen zu erkennen.
|
paul-scheinast
Anmeldungsdatum: 10. April 2015
Beiträge: 12
|
schau mal den Link an :http://www.hidemail.de/blog/datei-zeilenweise-einlesen.shtml Wie oben im Link ist es besser das ganze in eine schleife zu verpacken und bei der gefunden Zeile dann abzubrechen. Falls du eine Bestimmte Zeile haben möchtest kannst du auch den Dateihandle als Array verwenden:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | #!/usr/bin/perl
use Data::Dumper;
use strict; # Hilft Tippfehler zu finden. ;-)
use warnings; # Gibt ausführlichere Fehlermeldungen aus.
# use diagnostics; # Gibt noch ausführliche Meldungen aus.
use FindBin;
my $datei = 'table_streamlines_vel.csv';
open my $FH, '>>', $datei unless -e $datei;
open $FH, '+<', $datei;
my $notiz = (<$FH>)[1000];
print Dumper $notiz;
|
|
Tronde
(Themenstarter)
Anmeldungsdatum: 23. November 2006
Beiträge: 1640
|
Guten Abend und vielen Dank für die Erklärung. ☺ rklm schrieb: (Willst Du nicht lieber Ruby oder Python lernen? 😉)
Ich habe mich für Perl entschieden, da wir auf der Arbeit bereits etliche Perl-Scripts einsetzen. Um diese besser verstehen und neue Anwendungen erstellen zu können möchte ich mich gern in Perl einarbeiten. Darüber hinaus beherrsche ich bereits ein wenig Python und versuche es nicht einrosten zu lassen. 😉 Viele Grüße Tronde
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12821
|
Tronde schrieb:
rklm schrieb: (Willst Du nicht lieber Ruby oder Python lernen? 😉)
Ich habe mich für Perl entschieden, da wir auf der Arbeit bereits etliche Perl-Scripts einsetzen. Um diese besser verstehen und neue Anwendungen erstellen zu können möchte ich mich gern in Perl einarbeiten.
Verständlich. Für mich wurde Perl nach wenigen Wochen oft recht kryptisch, d.h., ich musste mir selbst bei von mir geschriebenem Code erst wieder mühsam erschließen, was er tut. Ich finde, Perl hat einfach eine zu unübersichtliche Syntax und dazu etliche Spezialtricks (wenn ich nur an in Regulären Ausdrücken eingebetteten Perl-Code denke...), die das Verständnis extrem erschweren und vermutlich nur von Menschen unfallfrei benutzt werden können, die a) ein speziell verdrahtetes Gehirn haben oder b) jeden Tag etliche Zeilen Perl programmieren.
Darüber hinaus beherrsche ich bereits ein wenig Python und versuche es nicht einrosten zu lassen. 😉
Lobenswert! 😉
|
Tronde
(Themenstarter)
Anmeldungsdatum: 23. November 2006
Beiträge: 1640
|
Hallo. Ich habe eine weitere Frage zum Perl Tutorial. Am Ende von Teil 3 wird folgender Code verwendet, um gleichzeitig die Kommandos 'm' und 'mv' verwenden zu können, um Notizen in der Liste zu verschieben:
| when ($kommando{'bewege'}) {
continue if length($notiz) ==
length($kommando{'bewege'})+1;
my($von, $zu) = split ':',
substr($notiz,
length($kommando{'bewege'}));
|
Dies funktioniert bei mir nicht. Ich kann ausschließlich das Kommando 'm' verwenden. Könnt ihr mir sagen, warum es nicht auch mit 'mv' funktioniert? Mein Code:
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 | #!/usr/bin/perl
# Dieses Perl-Programm wurde nach dem Perl-Tutorial aus Freies Magazin entwickelt.
# Teil 0: 2011-07 http://www.freiesmagazin.de/mobil/freiesMagazin-2011-07-bilder.html#11_07_perl0
# Teil 1: 2011-08 http://www.freiesmagazin.de/mobil/freiesMagazin-2011-08-bilder.html#11_08_perl1
# Teil 2: 2011-09 http://www.freiesmagazin.de/mobil/freiesMagazin-2011-09-bilder.html#11_09_perl2
# Teil 3: http://www.freiesmagazin.de/mobil/freiesMagazin-2011-11-bilder.html#11_11_perl3
use v5.18; # Verwende alle neuen Features aus Perl 5.18.
use strict; # Hilft Tippfehler zu finden. ;-)
use warnings; # Gibt ausführlichere Fehlermeldungen aus.
# use diagnostics; # Gibt noch ausführliche Meldungen aus.
use FindBin;
use File::Slurp;
chdir $FindBin::Bin;
my $datei = 'notizblock.txt';
my %kommando = ( bewege => 'm', loesche => 'd');
append_file($datei) unless -e $datei;
my @notizen = read_file($datei);
# @notiz = <$FH>; # <>-Operator liest eine Zeile aus dem Handle $FH. Statt <> kann auch readline $FH genutzt werden.
for my $nr (0 .. $#notizen)
{ print "[$nr] ", $notizen[$nr] }
print "Neue Notiz (ENTER, wenn keine; $kommando{'loesche'} loescht; $kommando{'bewege'} verschiebt): ";
my $notiz = <STDIN>;
given ( lc substr($notiz, 0, 1) ) {
when ("\n") { }
when (" ") {append_file($datei, $notiz) }
when ($kommando{'loesche'}) {
continue if length($notiz) == 2;
my $nr = int substr($notiz, 1);
splice(@notizen, $nr, 1) if $nr >= 0 and $nr <= $#notizen;
write_file($datei, @notizen);
}
when ($kommando{'bewege'}) {
continue if length($notiz) == length($kommando{'bewege'})+1;
my($von, $zu) = split ':',
substr($notiz, length($kommando{'bewege'}));
$von = int $von;
$zu = int $zu;
continue if $zu < 0 or $zu > $#notizen;
splice(@notizen, $zu, 0, splice(@notizen, $von, 1));
write_file($datei, @notizen);
}
}
Viele Grüße\\
Tronde
|
- bn.pl (1.8 KiB)
- Download bn.pl
- notizblock.txt (120 Bytes)
- Download notizblock.txt
|
paul-scheinast
Anmeldungsdatum: 10. April 2015
Beiträge: 12
|
Ich habe es mal etwas umgeschrieben so das er nun in die einzelnen blöcke geht, ich kann nur davon abraten experimental features zu nutzen, zum einen wegen der lesbarkeit zum anderen weil sie auch teilweise etwas buggy sind(aus eigener Erfahrung). 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 | #!/usr/bin/perl
use v5.18; # Verwende alle neuen Features aus Perl 5.18.
use strict; # Hilft Tippfehler zu finden. ;-)
use warnings; # Gibt ausführlichere Fehlermeldungen aus.
# use diagnostics; # Gibt noch ausführliche Meldungen aus.
use FindBin;
use File::Slurp;
chdir $FindBin::Bin;
my $datei = 'notizblock.txt';
my %kommando = ( bewege => 'm', loesche => 'd');
append_file($datei) unless -e $datei;
my @notizen = read_file($datei);
# @notiz = <$FH>; # <>-Operator liest eine Zeile aus dem Handle $FH. Statt <> kann auch readline $FH genutzt werden.
for my $nr (0 .. $#notizen)
{ print "[$nr] ", $notizen[$nr] }
print "Neue Notiz (ENTER, wenn keine; $kommando{'loesche'} loescht; $kommando{'bewege'} verschiebt): ";
my $notiz = <STDIN>;
my $command = ( lc substr($notiz, 0, 1) );
if ($command eq "\n") { }
if (" ") {append_file($datei, $notiz) }
if ($command eq $kommando{'loesche'}) {
continue if length($notiz) == 2;
my $nr = int substr($notiz, 1);
splice(@notizen, $nr, 1) if $nr >= 0 and $nr <= $#notizen;
write_file($datei, @notizen);
}
if ($command eq $kommando{'bewege'}) {
break unless length($notiz) == length($kommando{'bewege'})+1;
my($von, $zu) = split ':',
substr($notiz, length($kommando{'bewege'}));
$von = int $von;
$zu = int $zu;
continue if $zu < 0 or $zu > $#notizen;
splice(@notizen, $zu, 0, splice(@notizen, $von, 1));
write_file($datei, @notizen);
}
|
zu deiner frage warum nur ein Buchstabe geht:
in Zeile 26 wird ein substring genommen welcher nur den ersten Buchstaben zulässt.
|
Tronde
(Themenstarter)
Anmeldungsdatum: 23. November 2006
Beiträge: 1640
|
Guten Abend. Danke für deine Erklärung. Dass mit
nur ein einziges Zeichen eingelesen wird, leuchtet mir sofort ein. Völlig schleierhaft bleibt mir, wie der Beispielcode aus dem Tutorial dann funktionieren soll. Vielleicht habe ich dieses aber auch einfach falsch interpretiert. Auch dass die given/when-Struktur noch experimentell ist habe ich erst bei der Programmausgabe erfahren. Für ein kleines Programm, dass ich für die Arbeit schreibe, habe ich sie bereits durch if-elsif-else-Anweisungen ersetzt. Danke auch für deinen Hinweis hierzu. LG Tronde
|
paul-scheinast
Anmeldungsdatum: 10. April 2015
Beiträge: 12
|
Hallo, freut mich wenn ich Dir weiterhelfen konnte. Eventuell würde ein Umbau mit split zu einem Array, dann das Array abarbeiten helfen ? dann würde jeder schritt nach dem anderen gemacht werden ? Lg
Paul
|
Tronde
(Themenstarter)
Anmeldungsdatum: 23. November 2006
Beiträge: 1640
|
Hallo Paul. Vielleicht kannst du mir noch die Bedeutung von continue erläutern. Nehmen wir dazu ein Beispiel aus dem Tutorial:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | given ( lc substr($notiz, 0, 1) ) {
when ("\n") { }
when (" ") {append_file($datei, $notiz) }
when ($kommando{'loesche'}) {
continue if length($notiz) == 2;
my $nr = int substr($notiz, 1);
splice(@notizen, $nr, 1) if $nr >= 0 and $nr <= $#notizen;
write_file($datei, @notizen);
}
when ($kommando{'bewege'}) {
continue if length($notiz) == length($kommando{'bewege'})+1;
my($von, $zu) = split ':',
substr($notiz, length($kommando{'bewege'}));
$von = int $von;
$zu = int $zu;
continue if $zu < 0 or $zu > $#notizen;
splice(@notizen, $zu, 0, splice(@notizen, $von, 1));
write_file($datei, @notizen);
}
|
Im Tutorial steht dazu folgender Satz: Das Verlassen kann break auch jederzeit erzwingen und continue lässt zur nächsten when-Klausel springen.
Betrachtet man das obige Code-Beispiel, so wird dort mit
| given ( lc substr($notiz, 0, 1) )
|
das erste Zeichen des in $notiz gespeicherten Strings abgetrennt und zurückgegeben. Dieser Rückgabewert wird benötigt, um in den when-Klauseln entscheiden zu können, welche ausgeführt werden soll. Das Kommando
| continue if length($notiz) == 2;
|
sorgt dafür, dass der when-Block verlassen und zum nächsten when-Block gesprungen wird, falls der in $notiz gespeicherte String exakt zwei Zeichen lang ist. Habe ich das richtig verstanden? Ich verstehe das nämlich nicht ganz, da ich zum Löschen einer Notiz ja z.B. "d2" zum löschen der zweiten Notiz eingebe. Dann dürfte der when-Block aber gar nicht ausgeführt werden, da der String ja exakt zwei Zeichen lang ist. Bitte erleuchtet mich, denn ich bin verwirrt. Weiter unten leuchtet mir die continue-Anweisung hingegen ein:
| continue if $zu < 0 or $zu > $#notizen;
|
Hier soll der when-Block verlassen werden, wenn der Wert in $zu vor dem ersten Array-Element oder hinter dem letzten Array-Element liegt. Oder? Ich hoffe, ich konnte mich verständlich genug ausdrücken, um meine Frage beantworten zu können. LG Tronde
|
paul-scheinast
Anmeldungsdatum: 10. April 2015
Beiträge: 12
|
Hallo Tronde. Tronde schrieb: Hallo Paul. Vielleicht kannst du mir noch die Bedeutung von continue erläutern. Nehmen wir dazu ein Beispiel aus dem Tutorial:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | given ( lc substr($notiz, 0, 1) ) {
when ("\n") { }
when (" ") {append_file($datei, $notiz) }
when ($kommando{'loesche'}) {
continue if length($notiz) == 2;
my $nr = int substr($notiz, 1);
splice(@notizen, $nr, 1) if $nr >= 0 and $nr <= $#notizen;
write_file($datei, @notizen);
}
when ($kommando{'bewege'}) {
continue if length($notiz) == length($kommando{'bewege'})+1;
my($von, $zu) = split ':',
substr($notiz, length($kommando{'bewege'}));
$von = int $von;
$zu = int $zu;
continue if $zu < 0 or $zu > $#notizen;
splice(@notizen, $zu, 0, splice(@notizen, $von, 1));
write_file($datei, @notizen);
}
|
Im Tutorial steht dazu folgender Satz: Das Verlassen kann break auch jederzeit erzwingen und continue lässt zur nächsten when-Klausel springen.
Betrachtet man das obige Code-Beispiel, so wird dort mit
| given ( lc substr($notiz, 0, 1) )
|
das erste Zeichen des in $notiz gespeicherten Strings abgetrennt und zurückgegeben. Dieser Rückgabewert wird benötigt, um in den when-Klauseln entscheiden zu können, welche ausgeführt werden soll. Das Kommando
| continue if length($notiz) == 2;
|
sorgt dafür, dass der when-Block verlassen und zum nächsten when-Block gesprungen wird, falls der in $notiz gespeicherte String exakt zwei Zeichen lang ist. Habe ich das richtig verstanden? Ich verstehe das nämlich nicht ganz, da ich zum Löschen einer Notiz ja z.B. "d2" zum löschen der zweiten Notiz eingebe. Dann dürfte der when-Block aber gar nicht ausgeführt werden, da der String ja exakt zwei Zeichen lang ist.
meiner Meinung kann das nicht funktionieren weil der String immer nur 1 Zeichen lang ist, es macht Sinn zb. den String "d2" in 2 Teile zu splitten um zu wissen was getan wird und dann welche Notiz.
Ich tue mir zudem etwas schwer mit dem continue da ich es eigentlich nur als Codeblock hinter Schleifen kenne, da wird er nach jedem Statement ausgeführt(siehe perldoc http://perldoc.perl.org/functions/continue.html).
Eventuell wäre es sinnvoll das ganze neu zu programmieren dann könnte man es eventuell von Altlasten befreien, wenn du magst kann ich dabei helfen ? Oder gar was ganz anderes programmieren ? Bitte erleuchtet mich, denn ich bin verwirrt. Weiter unten leuchtet mir die continue-Anweisung hingegen ein:
| continue if $zu < 0 or $zu > $#notizen;
|
Hier soll der when-Block verlassen werden, wenn der Wert in $zu vor dem ersten Array-Element oder hinter dem letzten Array-Element liegt. Oder?
Genau, mit "$#arrayname" und "scalar @arrayname" bekommst du die Elemente zurück nur das mit $# die Elemente -1 zurück gegeben wird, das ist praktisch um das Array durch zugehen da du ja bei 0 beginnt bis Elemente -1, scalar liefert die anzahl an elementen.
Beispiel:
| use strict;
my @var = (0,1,2,3);
print scalar @var,"-",$#var,"\n";
|
Gibt "4-3" aus. Ich hoffe, ich konnte mich verständlich genug ausdrücken, um meine Frage beantworten zu können.
Ja alles bestens 😉
LG Tronde
|
Tronde
(Themenstarter)
Anmeldungsdatum: 23. November 2006
Beiträge: 1640
|
Guten Abend Paul. Danke für die erneute Erleuchtung. Ich werde das Tutorial mal mit Vorsicht zu Ende lesen und dann entscheiden, ob ich das Notizprogramm weiter schreibe. Evtl. fange ich dann noch mal von vorne an. Dann komme ich gern auf dich zurück. 😉 VG Tronde
|
paul-scheinast
Anmeldungsdatum: 10. April 2015
Beiträge: 12
|
Guten Abend Tronde, immer wieder gerne, ja bin allzeit bereit 😉 LG
Paul
|