Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]7895[/thread]

Kommaseparierte Listen bereichsweise ausgeben. (Seite 2)

Leser: 1


<< |< 1 2 3 >| >> 29 Einträge, 3 Seiten
sid burn
 2006-04-15 04:53
#64963 #64963
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Quote
Warum kann ich aber nicht direkt mit while() auf das Handle "LISTE" zugreifen?

Kannst du doch. Bei diesem Verfahren wird in jeder Schleife eine neue Zeile eingelesen. Diese Zeile steht dann in $_.

Code: (dl )
1
2
3
4
while (<LISTE>)
{
print; #Gibt bei jedem durchlauf eine Zeile aus.
}


Quote
open LISTE, "list.txt";
my @liste=<LISTE>;

Wenn du so etwas machst, dann wird die ganze Datei vorher in das Array eingelesen. Wenn du direkt das Filehandle in einer while Schleife machst, dann ist dies nicht der Fall. Dann wird immer nur Zeile für zeile eingelesen. Vor allem bei größeren Dateien empfiehlt sich die while Schleife.

Zum anderen empfiehlt es sich, wenn du alles einmal in einem Array eingelesen hast, das Filehandle sofort wieder zu schließen, wenn du es nicht mehr benötigst. Also das close ruhig vor der while schelife setzen. Am besten direkt hinter deiner zuweisung.

Quote
Dies produziert mir: "Use of uninitialized value in pattern match (m//) at ./test.pl line 13, <LISTE> line 1". Muss ich immer unbedingt den "Umweg" über "@liste" machen?

EDIT:
Kleine verbesserung. Diese Fehlermeldung kommt, wenn du deinem Skript nicht jedes benötigte Argument übergibst. Es wird nämlich "$key" in deiner Regex interpoliert. Wenn du nicht alle Argumente übergibst, dann gibt es auch kein $key, daher solltest du bei sowas auch am anfang überprüfen, ob überhaupt genug Elemente übergeben worden sind. Die Anmerkung unten mit $1 stimmt aber immer noch sofern, als das du die Überprüfung mit $1 erst im if Block machen solltest.
/EDIT:

Das hast du deswegen, weil in deiner if bedingung auch gleichzeitig $1 vorkommt. Das $1 existiert aber nur dann, wenn deine Regex auch wirklich auf den String gematcht hat, und es einen Wert mit "()" auslesen konnte. Wenn deine Regex nicht matcht. Dann gibt es kein $1, und dann kommt natürlich auch die Fehlermeldung das er eine uninitialiserte Variable benutzt. Besser wäre es also, die Überprüfung ob $1 im richtigen bereich ist, nochmal innerhalb des if Blockes zu machen.

Zum anderen musst du aufpassen. Wenn noch andere Daten in der Datei stehen als du angegeben hast, dann kann es auch sein das die regex falsche sachen erkennt, die du nicht möchtest...

---------
liste.txt
Code: (dl )
1
2
3
4
5
6
7
8
9
10
Hier steht irgendwas
bla
a=3,b=4,c=17,d=19
a=5,b=7,c=62,d=33
a=16,b=9,c=77,d=49
a=98,b=10,c=234,d=213
a=130,b=27,c=567,d=333
a=234,b=56,c=1024,d=789
a=444,b=231,c=1079,d=987
blub


listen.pl
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/perl -w

use strict;

die "$0: VALUE MIN MAX\n" if @ARGV != 3;
my ($key, $min, $max) = @ARGV;


open LISTE, "<", "liste.txt" or die $!;
while ( <LISTE> )
{
if ( m/$key=(\d+)/o )
{
print if $1 >= $min && $1 <= $max;
}
}
close LISTE;


Kleine Anmerkung, der Regex sollte man die Option /o hinzufügen. Ist etwas Performanter.\n\n

<!--EDIT|sid burn|1145063250-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
toby
 2006-04-15 04:57
#64964 #64964
User since
2006-04-14
66 Artikel
BenutzerIn
[default_avatar]
Edit:

Huh, als ich die Antwort von Dubu gelesen habe, probierte ich es sofort aus und in der zwischenzeit sind noch zwei weitere Beiträge hinzugekommen (und das noch um diese Zeit ;-)).

Ich danke Euch für Eure Hilfe und ausführlieche Erklärungen. Ich freue mich so nette Community gefunden zu haben!

Lieben Gruss und nochmals Danke!
Tobias\n\n

<!--EDIT|toby|1145063501-->
murphy
 2006-04-15 05:29
#64965 #64965
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
[quote=sid burn,15.04.2006, 01:53][...]
Quote
Dies produziert mir: "Use of uninitialized value in pattern match (m//) at ./test.pl line 13, <LISTE> line 1". Muss ich immer unbedingt den "Umweg" über "@liste" machen?

EDIT:
Kleine verbesserung. Diese Fehlermeldung kommt, wenn du deinem Skript nicht jedes benötigte Argument übergibst. Es wird nämlich "$key" in deiner Regex interpoliert. Wenn du nicht alle Argumente übergibst, dann gibt es auch kein $key, daher solltest du bei sowas auch am anfang überprüfen, ob überhaupt genug Elemente übergeben worden sind. Die Anmerkung unten mit $1 stimmt aber immer noch sofern, als das du die Überprüfung mit $1 erst im if Block machen solltest.
/EDIT:

Das hast du deswegen, weil in deiner if bedingung auch gleichzeitig $1 vorkommt. Das $1 existiert aber nur dann, wenn deine Regex auch wirklich auf den String gematcht hat, und es einen Wert mit "()" auslesen konnte. Wenn deine Regex nicht matcht. Dann gibt es kein $1, und dann kommt natürlich auch die Fehlermeldung das er eine uninitialiserte Variable benutzt. Besser wäre es also, die Überprüfung ob $1 im richtigen bereich ist, nochmal innerhalb des if Blockes zu machen.
[...][/quote]
Vorsicht: Der Fehler liegt, wie ich auch in meinem letzten Beitrag sagte, daran, dass $_ durch den Befehl $_=shift(@_); auf undef gesetzt wird, weil @_ leer ist.

Der Fehler liegt nicht an der Interpolation von $key. Wäre $key undefiniert, so würde das zwar auch einen Fehler produzieren, aber die Fehlermeldung wäre dann "Use of uninitialized value in regexp compilation [...]" anstatt "Use of uninitialized value in pattern match (m//) [...]". Unbeschadet dessen ist es eine gute Idee zu prüfen, ob alle nötigen Kommandozeilenparameter übergeben wurden.

Der Fehler liegt auch nicht an der Verwendung von $1 in der if-Bedingung. Die if-Bedingung ist völlig korrekt. Zum einen würde ein undefinierter Wert in einem booleschen Kontext keine Warnung erzeugen, sondern den Wahrheitswert "falsch" repräsentieren und zum anderen werden logische Ausdrücke im Kurzschlussverfahren ausgewertet, weshalb alles nach && nicht ausgeführt wird, wenn nicht die Mustersuche Erfolg vermeldet.

(edit: emoticons deaktiviert)\n\n

<!--EDIT|murphy|1145064643-->
When C++ is your hammer, every problem looks like your thumb.
sid burn
 2006-04-15 06:24
#64966 #64966
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
[quote=murphy,15.April.2006, 03:29]...und zum anderen werden logische Ausdrücke im Kurzschlussverfahren ausgewertet, weshalb alles nach && nicht ausgeführt wird, wenn nicht die Mustersuche Erfolg vermeldet.[/quote]
Stimmt, an der Tatsache habe ich gar nicht mehr dran gedacht.

Quote
- Der reguläre Ausdruck, den du verwendest um die Eingabezeilen auszuwerten, funktioniert, denke ich, nicht immer. Zum Beispiel kriegst du da Probleme, wenn eine Variable in deinen Eingabezeilen 'foo' heißt und jemand an der Kommandozeile angibt, dass nach 'o' gesucht werden soll. Dann erwischt dein regulärer Ausdruck immer auch 'foo'...

Aber nein das stimmt so nicht. Nur wenn hinter "foo" ein Gleichheitszeichen steht, und dahinter sofort eine Zahl folgt.

Zum anderen muss ich hier aber auch sagen das dies kein Problem der Regex ist, sondern eher das man hier eine unüberprüfte Eingabe eines Benutzers weiter verwendet.


Wenn man diese noch zusätzlich auf richtigkeit überprüfen möchte, dann sollte man dies direkt nach der Variablendeklaration mit my tun. Und dann alles Angeben was ein benutzer eingeben darf. Hier wäre das a,b,c,d. Man sollte also folgende Zeile hinzufügen.

Code: (dl )
die "Erstes Argument muss [a-d] sein\n"    unless $key =~ m/^[a-d]$/;


Wenn man Groß Kleinschreibung erlauben möchte dann entweder hier und in der Regex die Option /i anhängen, oder aber was ich empfehle oben /i benutzen, und $key dann mit "lc" in kleine buchstaben umwandeln. (Macht die untere Regex Performanter) Da in den Daten ja auch nur kleinbuchstaben vorkommen, würde das gehen.


-----------
Wenn ich das also nochmal zusammenfassen darf. Kann man es also so schreiben.

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/perl -w

use strict;

die "$0: VALUE MIN MAX\n" if @ARGV != 3;
my ($key, $min, $max) = @ARGV;
die "Erstes Argument muss [a-d] sein!\n" unless $key =~ m/^[a-d]$/i;
$key = lc $key;

open LISTE, "<", "liste.txt" or die $!;
while ( <LISTE> )
{
if ( m/$key=(\d+)/o && $1 >= $min && $1<= $max )
{
print;
}
}
close LISTE;


Allerdings würde ich die Überprüfung von $1 trotzdem im if Block schreiben, dass schaut mir irgendwie zu unübersichtlich aus.

Von der Performance her sollte es eigentlich egal sein? Da bei den gleichen Daten letztendlich bei beiden Schreibweisen die gleichen Bedingung überprüft werden müssen.

Allerdings würde ich das ganze auch mit "while ( <> ) { ... }" machen, anstatt eine Datei hart zu codieren.\n\n

<!--EDIT|sid burn|1145069426-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
toby
 2006-04-15 06:59
#64967 #64967
User since
2006-04-14
66 Artikel
BenutzerIn
[default_avatar]
Hallo, noch mal ich ;-)

mehrere Antwortende sagten hier, dass ich das Filehandle sofort, also noch for dem while() schliessen soll. Wie soll dann aber daraus gelesen werden, wenn es geschlossen ist? Ich habe es natürlich ausprobiert und tatsächlich, wenn ich for dem while() das Filehandle close, bekome ich aber folgendes:

Quote
readline() on closed filehandle LISTE at ./liste.pl line 14.

der code:

open FH, "list.txt";
close(FH);
while(<FH>){
print;
}


Sieht also aus und ist für mich logisch, dass man doch erst nach der Operation close'n kann, oder galt das für den Fall, wenn man ein Array gefüllt hat ( also FH öffnen, @liste füllen, FH closen, while(@liste)), dann muss ich aber wieder mit $_=shift(@liste) innerhalb von while() arbeiten und das wurde ja von Euch auch abgeraten, weil man besser mit dem Filehandler arbeiten soll... hmm... ? :confused:

Noch eine Frage:

@murphy: Du empfehlst das Einlesen der Datei (list.txt) folgendermassen:

Code: (dl )
1
2
3
4
5
my @lines;
{
open my $in, '<', 'list.txt' or die "Fehler beim Öffnen der Eingabedatei: $!\n";
@lines = <$in>;
}


sid burn erwähnte aber, dass dieses "auf einmal in ein Array Einlesen", bei grösseren Dateien nicht gut wäre. Es leuchtet mir ein, dass wie Du sagtest, mit meiner Variante "der globale Namensraum mit einem Filehandle verschmutzt wird", allerdings scheint mir das Argument das Problems mit dem "auf einmal Einlesen in ein Array" grösser, als der Vorteil des Sauberhaltens des globalen Namensraums, oder habe ich es hier wieder falsch verstanden?

Lieben Gruß :-)
Tobias\n\n

<!--EDIT|toby|1145070260-->
sid burn
 2006-04-15 07:14
#64968 #64968
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Quote
mehrere Antwortende sagten hier, dass ich das Filehandle sofort, also noch for dem while() schliessen soll. Wie soll dann aber daraus gelesen werden, wenn es geschlossen ist? Ich habe es natürlich ausprobiert und tatsächlich, wenn ich for dem while() das Filehandle close, bekome ich aber folgendes:

Du sollst das Filehandle nur dann sofort schließen, wenn du den Inhalt der Datei in einem Array eingelesen hast. Also folgendes gemacht hast.

Code: (dl )
1
2
3
4
5
6
7
8
open FILE, "<", "datei.txt";
@file = <FILE>;
close FILE;

for (@file)
{
print;
}

Da die Datei komplett im Array liegt, also im Speicher, kannst du das Filehandle sofort schließen. Wenn du das Filehandle danach natürlich noch benutzt, also z.B. in deiner while Schleife dann geht das natürlich nicht.

Allerdings macht es ja wenig Sinn das Filehandle zu benutzen wenn die Datei im Array liegt. Wenn man das Filehandle weiterhin benutzen würde, dann wäre das einlesen im Array reine Zeit- und Speicherverschwendung gewesen.

Zum anderen würde das auch nicht ohne weiteres gehen. Da du nämlich die komplette Datei in das Arrays eingelesen hast, zeigt das dateihandle auf EOF. Wenn du danach noch <FILE> aufrufst, würde nichts zurück geliefert werden. Also ein FALSE Wert.

Du müsstest die Position erstmal wieder mit "seek" auf den Anfang der Datei setzen damit du nach dem Einlesen des Arrays das Filehandle benutzen kannst. Aber die ganze Aktion wäre ja total Sinnlos.

Quote
Sieht also aus und ist für mich logisch, dass man doch erst nach der Operation close'n kann, oder galt das für den Fall, wenn man ein Array gefüllt hat ( also FH öffnen, @liste füllen, FH closen, while(@liste)), dann muss ich aber wieder mit $_=shift(@liste) innerhalb von while() arbeiten und das wurde ja von Euch auch abgeraten, weil man besser mit dem Filehandler arbeiten soll... hmm... ? :confused:

Nein, du itterierst dann über das Array mit einer foreach Schleife so wie oben angegeben. Hier einmal etwas ausführlicher. Deine Möglichkeit geht natürlich auch, würde ich aber nicht machen. Und dein Befehl würde ich als while Bedingung dann benutzen, und nicht innerhalb des while Blockes. Aber ein foreach ist hier schöner und besser lesbarer.

Code: (dl )
1
2
3
4
foreach $i (@file)
{
print $i;
}

Würde dann ebenfalls die komplette Zahl ausgeben. Wenn du das Skalar weg lässt, dann wird die Defaultvariable $_ gefüllt. Und das "each" kannst du auch weg lassen.

Quote
sid burn erwähnte aber, dass dieses "auf einmal in ein Array Einlesen", bei grösseren Dateien nicht gut wäre. Es leuchtet mir ein, dass wie Du sagtest, mit meiner Variante "der globale Namensraum mit einem Filehandle verschmutzt wird", allerdings scheint mir das Argument das Problems mit dem "auf einmal Einlesen in ein Array" grösser, als der Vorteil des Sauberhaltens des globalen Namensraums, oder habe ich es hier wieder falsch verstanden?

Bei größeren Skripten machen die Klammern schon einen Unterschied. Bei so einen kleinen Skript würde ich dafür nicht extra einen neuen Namensraum benutzen. Also keine Klammern machen.

Du kannst aber auch beides Benutzen. Soweit Klammern wie es nötig ist, und natürlich eine Datei nicht komplett im Speicher einlesen.\n\n

<!--EDIT|sid burn|1145071806-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
Ronnie
 2006-04-15 12:39
#64969 #64969
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Also mal die Minimalversion:
Code: (dl )
1
2
3
4
5
6
7
8
#!/usr/bin/perl

use strict;
use warnings;

die "usage: skript b 3 19 file.log\n" if @ARGV != 4;
my ($key, $min, $max) = splice @ARGV, 0, 3;
/,$key=(\d+)/ && $1 >= $min && $1 <= $max && print while (<>);

Das regex-Problem lässt sich einfach beheben in dem man das Komma noch berücksichtigt. Die Verwendung des o-Modifiers wäre möglich und sinnvoll da sich $key nicht ändert wärend der Schleife. Die Idee (<>) zu verwenden habe ich aufgegriffen, deshalb wurde auch das splice nötig.
pq
 2006-04-15 14:45
#64970 #64970
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
[quote=sid burn,15.04.2006, 04:24]Stimmt, an der Tatsache habe ich gar nicht mehr dran gedacht.[/quote]
ich denke gerade an die tatsache, dass gerade schon wieder
ein akkusativ für einen dativ geopfert wurde... SCNR =)

edit: s/ein dativ/einen dativ/\n\n

<!--EDIT|pq|1145116517-->
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
murphy
 2006-04-15 19:27
#64971 #64971
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
[quote=Ronnie,15.04.2006, 09:39][...]
Das regex-Problem lässt sich einfach beheben in dem man das Komma noch berücksichtigt. Die Verwendung des o-Modifiers wäre möglich und sinnvoll da sich $key nicht ändert wärend der Schleife. Die Idee (<>) zu verwenden habe ich aufgegriffen, deshalb wurde auch das splice nötig.[/quote]
Und was ist mit der Variablen am Zeilenanfang oder mit Leerzeichen vor oder hinter dem Komma oder Gleichheitszeichen? Reale Eingabedaten sind selten perfekt formatiert, also würde ich auf Nummer sicher gehen und den folgenden regulären Ausdruck verwenden:
Code: (dl )
m/(^|,)\s*$key\s*=\s*(\d+)/
When C++ is your hammer, every problem looks like your thumb.
murphy
 2006-04-15 19:28
#64972 #64972
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
[quote=pq,15.04.2006, 11:45][quote=sid burn,15.04.2006, 04:24]Stimmt, an der Tatsache habe ich gar nicht mehr dran gedacht.[/quote]
ich denke gerade an die tatsache, dass gerade schon wieder
ein akkusativ für ein dativ geopfert wurde... SCNR =)[/quote]
... für einen Dativ geopfert ... ;-P
When C++ is your hammer, every problem looks like your thumb.
<< |< 1 2 3 >| >> 29 Einträge, 3 Seiten



View all threads created 2006-04-14 16:54.