ubuntuusers.de

Perl : Suchen und Ersetzen mit arrays...

Status: Ungelöst | Ubuntu-Version: Ubuntu
Antworten |

drizzo

Anmeldungsdatum:
16. Oktober 2006

Beiträge: 68

Wohnort: Berlin

Servus Ihr,

mir ist so als hätte ich mir Perl vor einer längeren Zeit schon folgendes gemacht:
ich habe beispielsweise 2 Arrays:
Am Beispiel HTML Umlaute konvertieren:

@suchen = qw(a o u);
@ersetzen = qw(ä ö ü);

und kann es sehr einfach und schnell ersetzen...

#!/usr/bin/perl

@suchen = qw(a o u);
@ersetzen = qw(ä ö ü);

$mystr = "äh ich würde sagen nö\n";
print "Vorher--> $mystr";

$mystr =~ s/@suchen/@ersetzen/g;
print "Nachher--> $mystr";

Leider klappt es nicht, bin mir nun nicht mehr sicher, ob es wirklich so einfach war 😉

Danke für die Aufmerksamkeit.

Drizzo

Superdreadnought

Anmeldungsdatum:
31. Mai 2006

Beiträge: 563

soweit wie ich perl kenne (erst seit ein paar monaten eher weniger intensiver übung) wird das array hier im skalaren kontext interpretiert und gibt demnach die anzahl der elemente im array zurück.

du wirst das wohl mit einer while schleife erledigen müssen:

while(@suchen){
my $search = shift @suchen;
my $replace = shift @ersetzen;

$mystr =~ s/\Q$search\e/\Q$replace\E/g

korrigiert mich, wenn mein lösungsansatz (nicht getestet) falsch ist.

ps: sobald sid burn das hier liest, hast du sicherlich eine passende antwort ...

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

Nö das geht so nicht.
Der linke Teil einer Substitution ist eine Regex, und der Rechte Teil wird als String betrachtet.

In einer Regex werden nur Skalare interpoliert. "@suchen" hat also niht zur folge das die Elemente interpoliert werden. Sondern die Regex sucht einen String der mit "@" anfängt, gefolgt von "s" gefolgt von "u". u.s.w.

Der Rechte Teil wird als String betrachtet. Ein Array als String interpoliert bedeutet die Elemente werden einfach ausgegeben mit einem Leerzeichen als Trenner. Bzw. eigentlich wird der Trenner benutzt der in der Spezialvariable $" steht. Und dies ist Defaultmäßig ein einzelnes Leerzeichen.

Ich würde das ganze allerdings mit einem Hash Lösen und folgendermaßen schreiben.

my %trans = (
    'ä' => 'ä',
    'ö' => 'ö',
    'ü' => 'ü',
);

my $mystr = 'äh ich würde sagen nö';
print "Vorher--> $mystr\n";

for my $key ( keys %trans ) {
    $mystr =~ s/$key/$trans{$key}/g;
}

print "Nachhher--> $mystr\n";

Mit zwei Array geht es aber sicherlich auch.

my @suchen   = qw(ä ö ü);
my @ersetzen = qw(ä ö ü);

my $mystr = 'äh ich würde sagen nö';
print "Vorher--> $mystr\n";

$mystr =~ s/$suchen[$_]/$ersetzen[$_]/g for 0 .. $#suchen;
print "Nachher--> $mystr\n";

drizzo

(Themenstarter)

Anmeldungsdatum:
16. Oktober 2006

Beiträge: 68

Wohnort: Berlin

Danke Euch beiden für Eure Beiträge.

Ich habe es in einer leserlichen Form von:

$mystr =~ s/$suchen[$_]/$ersetzen[$_]/g for 0 .. $#suchen; 


geschrieben, da der Source code für jemanden, der weniger mit Perl zu tun hat noch zu lesen sein soll, wenngleich Deine Variante eleganter ist @Sid.

Und da Superdreadnought es schon angeschnitten hat in seinem "ps" 😉 ... nochmal ein zusätzliches Danke an Sid,
Deine Beiträge sind immer eine Hilfe, nicht nur weil sie meist die effizienteste Lösung parat haben, sondern weil sie
a) auch den Hintergund erklären, und auch
b) weil die eigenen Fehler auch nochmal analysiert werden.

Ein etwas anderes Problem, welches indirekt miteinander zu tun hat.
Wie würdet ihr folgendes lösen:

Das Suchen / Ersetzen wende ich auf Dateien an, die vorher, sofern es sie betrifft und sie existiert (code steht bis dato schon) als Backup kopiert wird.
Der Name des Backups lautet in dem Falle : "$alter_name . time()", was die sekunden seit 1970 anhängt. Wenn nun jedoch das Script 10 mal läuft, hat man
quasi 10 backups. Hat jemand eine Idee, wie man mit möglichst wenig Aufwand, die letzten drei aufhebt, den Rest beim erstellen des Neuen "droppt" ?

/bow
Alex

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

Also eine Möglichkeit die mir jetzt auf die schnelle einfällt wäre einfach mit glob die Dateien in einem Array zu speichern, und wenn das Array mehr als 3 Dateien enthält wird die erste Datei gelöscht, und die Datei aus dem Array entfernt, und das solange wie das Array größer als 3 ist.

Hier mal den code wie ich 10 Dateien angelegt habe

#!/usr/bin/perl
use warnings;
use strict;

for ( 0 .. 10 ) {
    my $file = 'backup-'.time();
    open my $fh, '>', $file  or  die $!;
    print "Created: $file\n";
    sleep 2;
}

Und zum löschen dann das

#!/usr/bin/perl
use warnings;
use strict;

my @files = glob('backup-*');
unlink shift @files while @files > 3;

drizzo

(Themenstarter)

Anmeldungsdatum:
16. Oktober 2006

Beiträge: 68

Wohnort: Berlin

Wieder schön kurz und effektiv. Mein Bedenken: ist es auch automatisch durch glob() sortiert ?
Ich habe desöfteren Tests gemacht, war alles einwandfrei, aber in "pelrdoc -f glob" steht nichts davon, dass es IMMER automatisch sortiert ist.

Um sicher zu gehen eventuell ein sort() mit einbauen ?

@files = sort @files;
unlink shift @files while @files > 3; 

Grüße aus Berlin
Alex

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

Es steht zwar nichts dort von einem Sort, aber er sortiert automatisch nach dem ASCII Alphabet. Ein extra sort() ist also eigentlich überflüssig.

drizzo

(Themenstarter)

Anmeldungsdatum:
16. Oktober 2006

Beiträge: 68

Wohnort: Berlin

Danke dir 😉

Alex

Antworten |