2016-04-15 2 views
1

Я написал следующий скрипт, потому что мне нужно сделать некоторую очистку в некоторых файлах. У меня есть определенное количество шестнадцатеричных символов, которые необходимо изменить на другой набор шестнадцатеричных символов (т. Е. От нуля до пробела, см. Ниже). Я написал следующий сценарий, моя проблема в том, что он заменяет только первое появление и ничего больше.Заменить несколько шестнадцатеричных значений

Я пробовал/g, как обычный шаблон sed, но он не работает. Есть ли способ сделать это и заменить все матчи?

(Причина, по которой я использовал $line =~ s/..., состоит в том, что я думаю, что его более аккуратный и более удобный в обслуживании, и этот сценарий должен быть доступен и запускаться иногда другими, которым может потребоваться отредактировать шестнадцатеричные значения, подлежащие замене) , Другая причина заключается в том, что мне нужно изменить значение от 10 + гексагональных значений до эквивалентного количества, так что огромный один лайнер будет трудно читать. Заранее спасибо.

#!/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

Я думаю, что при замене ровно один символ ровно один другой символ, 'tr' будет лучше (быстрее), то есть' $ строка = ~ тр/\ x00/\ x20 /; '(не'/г '). – PerlDuck

+0

Я собираюсь попробовать, файлы огромны, поэтому я сравню время и дам вам знать! Спасибо за предложение. Я не помню с головы, но я думаю, tr может также заменить диапазон символов одним конкретным, в духе tr/\ x00-x20/\ x20 /; – onlyf

+1

tr - хорошее предложение. Один tr может переводить столько символов, сколько вы хотите. например 'tr/abc/xyz /' изменит a на x, b на y и т. д. –

ответ

0

Обновление: прочитайте комментарии для оповещения об этом ответе.

Вот один из способов, который будет позволит вам сохранить список поиска регулярных выражений/заменяет в верхней части вашего сценария красивым и чистым для удобства просмотра и изменения:

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 

Выход:

xxxyyyccc 
yyycccddd 
xyxyxyxyx 
+1

Проблема с этим подходом заключается в том, что он не может обрабатывать '['a', 'x'], ['x', ' y '] ' – ikegami

+0

Хороший улов! Спасибо что подметил это. – stevieb

0

/g будет делать то, что вы хотите. Если это, кажется, не работает, добавить некоторые отладки:

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

И в цикле:

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

Использования тра с парными разделителями вместо этого может быть очень читаемым/ремонтопригоден:

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

Кроме того, рассмотреть вопрос о добавлении use autodie;

0

tr/// является вероятно, ваш лучший выбор здесь (поскольку вы имеете дело с постоянными заменами одного персонажа). Следующее - более общее решение. не

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

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

s/($pat)/$replacements{$1}/g; 
Смежные вопросы