2016-04-15 6 views
1

Ich habe das folgende Skript geschrieben, weil ich in einigen Dateien etwas aufräumen muss. Ich habe eine bestimmte Anzahl von Hex-Zeichen, die in eine andere Menge von Hex-Zeichen geändert werden müssen (dh Null in Leerzeichen, siehe unten). Ich habe das folgende Skript geschrieben, mein Problem ist, dass es nur das erste Vorkommen und nichts anderes ersetzt.Ersetze mehrere Hexadezimalwerte

Ich habe versucht, die/g wie ein normales sed-Muster, aber es funktioniert nicht. Gibt es eine Möglichkeit, dies zu tun und alle Übereinstimmungen zu ersetzen?

(Der Grund, warum ich kein $line =~ s/... verwendet habe, ist, weil ich denke, dass es so übersichtlicher und wartungsfreundlicher ist, und dieses Skript muss von anderen Benutzern geöffnet und ausgeführt werden, die die zu ersetzenden Hexadezimalwerte bearbeiten müssen) . Ein weiterer Grund ist, dass ich von 10 Hex-Werten auf eine äquivalente Menge ändern muss, so dass ein großer Liner schwer zu lesen wäre. Vielen Dank im Voraus.

#!/usr/bin/perl 


use strict; 
use warnings; 

my $filebase = shift || "testreplace.txt"; 
my $filefilter = shift || "testf"; 

open my $fh1, '>', 'testreplaceout'; 

# Iterate over file and read lines 
open my $file1, '<', $filebase; 

while (my $line = <$file1>) 
{ 
    chomp($line); 

    for ($line) { 
      s/\x00/\x20/g; 
      s/\x31/\x32/g; 
    } 

    print {$fh1} "$line \n"; 


} 
+3

Ich denke, wenn mit genau einem anderen Charakter genau ein Zeichen zu ersetzen, 'tr' wäre besser (schneller), dh' $ line = ~ tr/\ x00/\ x20 /; '(kein'/g '). – PerlDuck

+0

Ich werde es versuchen, die Dateien sind riesig, also werde ich mal vergleichen und Sie wissen lassen! Danke für den Vorschlag. Ich erinnere mich nicht an den Kopf, aber ich denke, dass tr auch eine Reihe von Charakteren mit einer bestimmten ersetzen kann, im Sinne von tr/\ x00-x20/\ x20 /; – onlyf

+1

tr ist ein guter Vorschlag. Ein einzelner tr kann so viele Zeichen wie Sie möchten übersetzen. z.B. 'tr/abc/xyz /' ändert a nach x, b in y usw. –

Antwort

0

Update: Lesen Sie Kommentare für Vorbehalte dieser Antwort.

Hier ist eine Möglichkeit, dass Sie Ihre Liste der regex Suche zu halten erlauben werden/ersetzt am Anfang des Skripts schön und sauber für eine einfache Anzeige und Änderung:

use warnings; 
use strict; 

my @re_list = (
    ['a', 'x'], 
    ['b', 'y'], 
); 

while (my $line = <DATA>){ 
    for my $re (@re_list){ 
     $line =~ s/$re->[0]/$re->[1]/g; 
    } 
    print $line; 
} 

__DATA__ 
aaabbbccc 
bbbcccddd 
ababababa 

Ausgang:

xxxyyyccc 
yyycccddd 
xyxyxyxyx 
+1

Das Problem mit diesem Ansatz ist, dass es nicht mit '['a', 'x'], ['x', 'umgehen kann. y '] ' – ikegami

+0

Schöner Fang! Danke, dass du darauf hingewiesen hast. – stevieb

0

/g wird tun, was Sie wollen. Wenn es nicht zu funktionieren scheint, fügen Sie einige Debug:

use Data::Dumper; 
$Data::Dumper::Useqq = $Data::Dumper::Terse = 1; 

Und in der Schleife:

print Dumper($line); 
for ($line) { 
     s/\x00/\x20/g; 
     s/\x31/\x32/g; 
} 
print Dumper($line); 

mit paarigen Trennzeichen verwenden tr stattdessen kann sehr gut lesbar sein/wartbar:

$line =~ tr[\x00\x31] 
        [\x20\x32]; 
auch

betrachten use autodie; Zugabe

0

tr/// ist wahrscheinlich Ihre beste Wette hier (da Sie mit ständigen Ersatz einzelner Zeichen zu tun haben). Das Folgende ist eine allgemeinere Lösung.

my %replacements = (
    'foo' => 'bar', 
    'bar' => 'baz', 
); 

my $pat = join '|', map quotemeta, keys(%replacement); 

s/($pat)/$replacements{$1}/g;