Array sortiert mit unsortierten Daten füllen

Array sortiert mit unsortierten Daten füllen

am 07.03.2006 19:05:13 von Marcel Dix

Hi!

Ich habe eine Schleife die mir Dateinamen nach Vorgaben erzeugt.
1-1.abc
2-1.abc
3-1.abc
usw...
1-1.def
2-1.def
3-1.def

Diese Dateien sollen per mail-skript an eine eMail angehangen werden.
Und zwar immer 1-1.abc und 1-1.def mit einer mail,
2-1.abc und 2-1.def mit einer mail usw...

Ich habe noch keinen blassen Schimmer, wie ich an dieses Problem
herangehen soll...

Am besten wäre ja, wenn ich das gleich in der Schleife mit in ein Array
pushen könnte und dann die doppelten Dateinamen einfach
zwischenschieben... weiß aber net wie...

Ich hoffe mir kann jemand kleine Denkanstöße geben (ohne gleich auf
perldoc klopfen)

Danke schonmal


Ciao
Marcel

Re: Array sortiert mit unsortierten Daten füllen

am 07.03.2006 20:45:59 von Christian Winter

Marcel Dix schrieb:
> Hi!
>
> Ich habe eine Schleife die mir Dateinamen nach Vorgaben erzeugt.
> 1-1.abc
> 2-1.abc
> 3-1.abc
> usw...
> 1-1.def
> 2-1.def
> 3-1.def
>
> Diese Dateien sollen per mail-skript an eine eMail angehangen werden.
> Und zwar immer 1-1.abc und 1-1.def mit einer mail,
> 2-1.abc und 2-1.def mit einer mail usw...

Poste doch einmal das Code-Schnipsel mit der Schleife (oder
die relevanten Teile davon in lauffähiger Form), es macht
keinen Sinn hier das Rad neu zu erfinden.

> Ich habe noch keinen blassen Schimmer, wie ich an dieses Problem
> herangehen soll...
>
> Am besten wäre ja, wenn ich das gleich in der Schleife mit in ein Array
> pushen könnte und dann die doppelten Dateinamen einfach
> zwischenschieben... weiß aber net wie...

Wie erzeugst Du die Dateinamen? Es sollte doch nicht schwierig
sein, an dieser Stelle erstmal nur den Prefix-Teil zu erzeugen
("1-1", "2-1" usw.), ihn auf ein Array zu schieben und dann
jeweis einen String "x-y.abc" und "x-y.def" daraus zu bauen
(und weiterzuverwenden).

Aber ohne zu sehen was Du versucht hast ist es schwer nachzu-
vollziehen, womit Du ein Problem hast.

> Ich hoffe mir kann jemand kleine Denkanstöße geben (ohne gleich auf
> perldoc klopfen)

Eher auf die FAQ der Gruppe, bzw. deren Verweis auf
http://www.worldmusic.de/perl/checkliste.html
(und die Bitte darin, relevanten Code zu posten).

Viele Grüße
-Christian

Re: Array sortiert mit unsortierten Daten füllen

am 08.03.2006 11:17:32 von Marcel Dix

Christian Winter schrieb:
> Wie erzeugst Du die Dateinamen?

Hallo Christian!

Das Skript soll später mal die Auswertung eines PBEM-Spieles
Automatisieren, also email einlesen, Programm starten, Reports
verschicken usw...

Meine Subroutine in der - nach meiner Meinung - man das mit einbauen
könnte. Eigentlich dient die dazu, die Report-Dateien umzubenennen.



$turn = 1; # wird in einer anderen sub erzeugt

@endings = ('abc','def');

name_reports(@endings);


sub name_reports {
foreach my $part (@_) {
my @repfiles = glob("$reportdir/*.$part");

foreach (@repfiles) {

unless ( $_ =~ m/\-{1}/ ) {
my @path = split(/\//,$_);
my $len = scalar(@path);
$newname = join("\-$turn\.", split(/\./, $path[$len-1], 2));
$newfile = "$reportdir/$newname";
rename($_, $newfile);
}
else { next }
}
}
}



Vielleicht gibt es dir die Informationen die Du suchst.

Ach ja :)

Perl 5.8.7
Ubuntu Linux
Als VMWare-Guest auf XP-Pro-Host
512 MB RAM
AthlonXP 2400+


Bye
Marcel

Re: Array sortiert mit unsortierten Daten füllen

am 08.03.2006 16:23:46 von Christian Winter

Marcel Dix schrieb:

> Das Skript soll später mal die Auswertung eines PBEM-Spieles
> Automatisieren, also email einlesen, Programm starten, Reports
> verschicken usw...
>
> Meine Subroutine in der - nach meiner Meinung - man das mit einbauen
> könnte. Eigentlich dient die dazu, die Report-Dateien umzubenennen.
>
>
>
> $turn = 1; # wird in einer anderen sub erzeugt
>
> @endings = ('abc','def');
>
> name_reports(@endings);
>
>
> sub name_reports {
> foreach my $part (@_) {
> my @repfiles = glob("$reportdir/*.$part");
>
> foreach (@repfiles) {
>
> unless ( $_ =~ m/\-{1}/ ) {
> my @path = split(/\//,$_);
> my $len = scalar(@path);
> $newname = join("\-$turn\.", split(/\./, $path[$len-1], 2));
> $newfile = "$reportdir/$newname";
> rename($_, $newfile);
> }
> else { next }
> }
> }
> }
>
>

>
> Vielleicht gibt es dir die Informationen die Du suchst.

Ja, jetzt wird die Problemstellung klarer. Du durchläufst das
ganze einmal für '.abc'-Dateien, dann nochmal für '.def'-Dateien.

Ich persönlich würde die Logik ein wenig abändern und erstmal
alle 'abc'-Dateinamen sortiert holen (ich geh mal davon aus, dass
ex für jede X.abc auch eine X.def gibt), die bereits umbenannten
rauswerfen und mir daraus die Stammnummer in ein Array holen.

Das Array läßt sich dann abklappern und für jede Endung das Umbenennen
durchführen. Gleichzeit musst Du ohnehin die neue Filenummer (-$turn)
einbauen, das kannst Du gleich auf dem bestehenden Array machen, das
Du am Ende der sub zurückliefern kannst.

Würde bei mir also ungefähr so aussehen:
------------------------------------------------------------ -
#!/usr/bin/perl

use strict;
use warnings;

my @endings = qw/abc def/;
my $reportdir = "irgendwas";
my $turn = 1;

my @filenums = name_reports($turn, $reportdir, @endings);
# in @filenums stehen jetzt ("1-1", "2-1", etc.) und können
# für die Mail-Funktion zusammen mit @endings verwendet werden

mail_reports( \@filenums, \@endings );

sub name_reports
{
my ($turn, $repdir, @endings) = @_;
chdir( $repdir );

my @repfiles = sort { $a <=> $b } # Numerisch sortieren
map { m|^(\d+)| && $1 } # Nummer extrahieren
grep { /^\d+\./ } # Nur neue Dateien
glob( "*." . $endings[0] ); # '.abc'-Dateien

foreach ( @repfiles )
{
my $oldfile = $_;
$_ .= "-$turn"; # <- verändert auch den Wert in @repfiles
for my $ext ( @endings )
{
rename("$oldfile.$ext", "$_.$ext");
}
}

chdir("..");
return @repfiles;
}

sub mail_reports
{
my $repdir = shift;
my @files = @{shift @_};
my @endings = @{shift @_};

foreach my $filebase ( @files )
{
# Die Mail zusammmenbauen
foreach my $ext ( @endings )
{
# Datei "$repdir/$filebase.$ext" anhängen
}
# Die Mail versenden
}
}
------------------------------------------------------------ -

HTH
-Christian

Re: Array sortiert mit unsortierten Daten füllen

am 09.03.2006 17:06:03 von Marcel Dix

Christian Winter schrieb:
> Marcel Dix schrieb:
>
>> Das Skript soll später mal die Auswertung eines PBEM-Spieles
>> Automatisieren, also email einlesen, Programm starten, Reports
>> verschicken usw...
>>
>> Meine Subroutine in der - nach meiner Meinung - man das mit einbauen
>> könnte. Eigentlich dient die dazu, die Report-Dateien umzubenennen.
>>
>>
>>
>> $turn = 1; # wird in einer anderen sub erzeugt
>>
>> @endings = ('abc','def');
>>
>> name_reports(@endings);
>>
>>
>> sub name_reports {
>> foreach my $part (@_) {
>> my @repfiles = glob("$reportdir/*.$part");
>>
>> foreach (@repfiles) {
>>
>> unless ( $_ =~ m/\-{1}/ ) {
>> my @path = split(/\//,$_);
>> my $len = scalar(@path);
>> $newname = join("\-$turn\.", split(/\./, $path[$len-1], 2));
>> $newfile = "$reportdir/$newname";
>> rename($_, $newfile);
>> }
>> else { next }
>> }
>> }
>> }
>>
>>

>>
>> Vielleicht gibt es dir die Informationen die Du suchst.
>
> Ja, jetzt wird die Problemstellung klarer. Du durchläufst das
> ganze einmal für '.abc'-Dateien, dann nochmal für '.def'-Dateien.
>
> Ich persönlich würde die Logik ein wenig abändern und erstmal
> alle 'abc'-Dateinamen sortiert holen (ich geh mal davon aus, dass
> ex für jede X.abc auch eine X.def gibt), die bereits umbenannten
> rauswerfen und mir daraus die Stammnummer in ein Array holen.
>
> Das Array läßt sich dann abklappern und für jede Endung das Umbenennen
> durchführen. Gleichzeit musst Du ohnehin die neue Filenummer (-$turn)
> einbauen, das kannst Du gleich auf dem bestehenden Array machen, das
> Du am Ende der sub zurückliefern kannst.
>
> Würde bei mir also ungefähr so aussehen:
> ------------------------------------------------------------ -
> #!/usr/bin/perl
>
> use strict;
> use warnings;
>
> my @endings = qw/abc def/;
> my $reportdir = "irgendwas";
> my $turn = 1;
>
> my @filenums = name_reports($turn, $reportdir, @endings);
> # in @filenums stehen jetzt ("1-1", "2-1", etc.) und können
> # für die Mail-Funktion zusammen mit @endings verwendet werden
>
> mail_reports( \@filenums, \@endings );
>
> sub name_reports
> {
> my ($turn, $repdir, @endings) = @_;
> chdir( $repdir );
>
> my @repfiles = sort { $a <=> $b } # Numerisch sortieren
> map { m|^(\d+)| && $1 } # Nummer extrahieren
> grep { /^\d+\./ } # Nur neue Dateien
> glob( "*." . $endings[0] ); # '.abc'-Dateien
>
> foreach ( @repfiles )
> {
> my $oldfile = $_;
> $_ .= "-$turn"; # <- verändert auch den Wert in @repfiles
> for my $ext ( @endings )
> {
> rename("$oldfile.$ext", "$_.$ext");
> }
> }
>
> chdir("..");
> return @repfiles;
> }
>
> sub mail_reports
> {
> my $repdir = shift;
> my @files = @{shift @_};
> my @endings = @{shift @_};
>
> foreach my $filebase ( @files )
> {
> # Die Mail zusammmenbauen
> foreach my $ext ( @endings )
> {
> # Datei "$repdir/$filebase.$ext" anhängen
> }
> # Die Mail versenden
> }
> }
> ------------------------------------------------------------ -
>
> HTH
> -Christian

Hallo Christian!

Danke erstmal für deine Mühe! Deine Idee hatte ich auch schon im
Hinterkopf, aber dann doch die andere Variante gewählt...

So ganz hab ich das aber nicht verstanden.
Genauer gesagt die Zeilen:

>
> mail_reports( \@filenums, \@endings );
>

und

> sub mail_reports
> {
> my $repdir = shift;
> my @files = @{shift @_};
> my @endings = @{shift @_}; <== Hier Zeile 44
>

Der Rest ist klar und einleuchtend.
Das Skript bringt bei mir auch eine Fehlermeldung in :

Can't use an undefined value as an ARRAY reference at ./test.pl line 44.

Was soll das heißen?

Best regards
Marcel

Re: Array sortiert mit unsortierten Daten füllen

am 09.03.2006 17:17:59 von Ingo Menger

Marcel Dix schrieb:


> So ganz hab ich das aber nicht verstanden.
> Genauer gesagt die Zeilen:
>
> >
> > mail_reports( \@filenums, \@endings );

Hier werden Referenzen auf Arrays übergeben.


>
> und
>
> > sub mail_reports
> > {
> > my $repdir =3D shift;
> > my @files =3D @{shift @_};
> > my @endings =3D @{shift @_}; <== Hier Zeile 44

Und hier werden diese Referenzen wieder dereferenziert (d.h. die
referierten Arrays werden kopiert). Das ist eigentlich nicht nötig,
man könnte
my $files =3D shift;
my $endings =3D shift;
schreiben und mit @$files bzw @$endings auf die Arrays zugreifen.

> Das Skript bringt bei mir auch eine Fehlermeldung in :
>
> Can't use an undefined value as an ARRAY reference at ./test.pl line 44.
>
> Was soll das heißen?

Er kann einen undefinierten Wert nicht als ARRAY Referenz verwenden.
(Welches ARRAY sollte denn der Wert undef auch referieren?)
Dies weist auf den Fehler hin, daß der sub mail_report nur zwei
Parameter übergeben werden, aber in der sub 3 verwendet werden.

Re: Array sortiert mit unsortierten Daten füllen

am 09.03.2006 18:52:51 von Marcel Dix

Christian schrieb:

> my @repfiles = sort { $a <=> $b } # Numerisch sortieren
> map { m|^(\d+)| && $1 } # Nummer extrahieren
> grep { /^\d+\./ } # Nur neue Dateien
> glob( "*." . $endings[0] ); # '.abc'-Dateien

Auf was muss man matchen, wenn der neue Dateiname nicht nur eine Nummer
ist, sondern auf base36 basiert?

Reicht da ein einfaches [\d\w] ?
Die Dateinamen können zB. 0zf8.abc oder s4fj.abc sein und sollten dann
hinterher halt 0zf8-1.abc oder s4fj-1.abc .

Wie muss man da das Pattern gestalten?
Außerdem ist bei mir in @repfiles nix drin :(

Viele Fragen...


Bye
Marcel

Re: Array sortiert mit unsortierten Daten füllen

am 10.03.2006 08:36:25 von Christian Winter

Marcel Dix schrieb:
> So ganz hab ich das aber nicht verstanden.
> Genauer gesagt die Zeilen:
>
>>mail_reports( \@filenums, \@endings );
>>
> und
>
>>sub mail_reports
>>{
>> my $repdir = shift;
>> my @files = @{shift @_};
>> my @endings = @{shift @_}; <== Hier Zeile 44
>
> Der Rest ist klar und einleuchtend.
> Das Skript bringt bei mir auch eine Fehlermeldung in :
>
> Can't use an undefined value as an ARRAY reference at ./test.pl line 44.

Irrtum vom Amt, da hat meine CopyPaste versagt.

Der Aufruf muß natürlich heissen
mail_reports( $reportdir, \@filenums, \@endings );

Wie Ingo schon geschrieben hat werden die Arrays als Referenz
übergeben. Das ist notwendig, da sie ansonsten "flach" gemacht
würden und an die subs nur eine Liste mit allen Elementen über-
geben würde.

Als Beispiel:

my @a = (1,2);
my @b = (3,4);
aufruf(@a,@b);

sub aufruf
{
print "@_",$/; # @_ enthält jetzt (1,2,3,4)
}

Ausführlich geschrieben würde das Dereferenzieren in mail_reports
so aussehen:
sub mail_reports
{
my $repdir = shift;
my $fileref = shift; # Verwendet implizit @_
my @files = @{$fileref};
my $endsref = shift;
my @endings = @{$endsref};
....

-Christian

Re: Array sortiert mit unsortierten Daten füllen

am 10.03.2006 08:36:39 von Christian Winter

Marcel Dix schrieb:
> Christian schrieb:
>
>
>>my @repfiles = sort { $a <=> $b } # Numerisch sortieren
>> map { m|^(\d+)| && $1 } # Nummer extrahieren
>> grep { /^\d+\./ } # Nur neue Dateien
>> glob( "*." . $endings[0] ); # '.abc'-Dateien
>
>
> Auf was muss man matchen, wenn der neue Dateiname nicht nur eine Nummer
> ist, sondern auf base36 basiert?
>
> Reicht da ein einfaches [\d\w] ?

Würde reichen, ich würde aber zwecks Lesbarkeit auf die
vorgefertigte Klasse [[:alnum:]] zurückgreifen.

> Die Dateinamen können zB. 0zf8.abc oder s4fj.abc sein und sollten dann
> hinterher halt 0zf8-1.abc oder s4fj-1.abc .
>
> Wie muss man da das Pattern gestalten?
> Außerdem ist bei mir in @repfiles nix drin :(

Zelzam. Hier funktionierts.

-Christian

Re: Array sortiert mit unsortierten Daten füllen

am 10.03.2006 11:48:12 von Ingo Menger

Marcel Dix schrieb:


> Wie muss man da das Pattern gestalten?

Man muß gar nix, denn: There is always more than one way.
Nimm doch einfach: [^.]+
Alles außer Punkt.

Re: Array sortiert mit unsortierten Daten füllen

am 10.03.2006 12:46:20 von Marcel Dix

Christian Winter schrieb:
>
> Irrtum vom Amt, da hat meine CopyPaste versagt.
>
> Der Aufruf muß natürlich heissen
> mail_reports( $reportdir, \@filenums, \@endings );
>

Geändert und gefreut!

Auch das [[:alnum:]] hab ich mit eingebaut und es funktioniert
wunderbar. Außer das sort( $a<=>$b ) meckert jetzt rum, weil ich ja
jetzt nicht nur numerische Zeichen drin hab und daher auch nicht mehr
nach denen sortiert werden kann.

Gibt es da eine Möglichkeit das anzupassen, oder kann man das einfach
ignorieren?

Auch wäre es nicht schlecht, wenn man das nach:

123456789abcdef...z sortieren könnte, also erst die Zahlen und dann die
Buchstaben.

Re: Array sortiert mit unsortierten Daten füllen

am 10.03.2006 13:44:59 von Ingo Menger

Marcel Dix schrieb:

> Auch wäre es nicht schlecht, wenn man das nach:
>
> 123456789abcdef...z sortieren könnte, also erst die Zahlen und dann die
> Buchstaben.

Also alphabetisch aufsteigend (gemäß ASCII-Code).
Dies sollte eigentlich cmp statt <=3D> leisten.

Re: Array sortiert mit unsortierten Daten füllen

am 10.03.2006 15:10:16 von Christian Winter

Ingo Menger schrieb:
> Marcel Dix schrieb:
>
>
>>Auch wäre es nicht schlecht, wenn man das nach:
>>
>>123456789abcdef...z sortieren könnte, also erst die Zahlen und dann die
>>Buchstaben.
>
> Also alphabetisch aufsteigend (gemäß ASCII-Code).
> Dies sollte eigentlich cmp statt <=> leisten.

Allerdings funktioniert das nur wenn alle Zahlen gleich lang sind
und nur entweder Groß- oder Kleinbuchstaben drin sind.
Ansonsten muß das noch zusätzlich abgefangen werden:

sort { length $a <=> length $b || lc $a cmp lc $b }

sortiert dann auch Base36-konform.

-Christian