2010-06-07 3 views
2

Я использую Perl для очистки некоторых файлов и сталкиваюсь с некоторыми проблемами производительности. Одна из основных частей моего кода включает стандартизацию полей имени. У меня есть несколько разделов, которые выглядят следующим образом:Perl Regex - Конденсирующие группы для поиска/замены

sub substitute_titles 
{ 
    my ($inStr) = @_; 
    ${$inStr} =~ s/ PHD./ PHD /; 
    ${$inStr} =~ s/ P H D/PHD /; 
    ${$inStr} =~ s/ PROF./ PROF /; 
    ${$inStr} =~ s/ P R O F/PROF /; 
    ${$inStr} =~ s/ DR./ DR /; 
    ${$inStr} =~ s/ D.R./ DR /; 
    ${$inStr} =~ s/ HON./ HON /; 
    ${$inStr} =~ s/ H O N/HON /; 
    ${$inStr} =~ s/ MR./ MR /; 
    ${$inStr} =~ s/ MRS./ MRS /; 
    ${$inStr} =~ s/ M R S/MRS /; 
    ${$inStr} =~ s/ MS./ MS /; 
    ${$inStr} =~ s/ MISS./ MISS /; 
} 

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

Есть ли лучший способ реализовать такую ​​логику, чем то, что я делаю сейчас?

Благодаря

Edit: Быстрый записные, не все функции, заменяющие только удаление периодов и пространства. Есть строка делеции, SOUNDEX группы и т.д.

+2

Если вы пытаетесь сопоставить периоды, разве вам не хватает некоторых обратных косых черт? Помните, что '.' является метасимволом, который соответствует периоду, но также и о чем-либо еще. – cjm

+0

кричит, хорошая точка. Спасибо что подметил это. – brydgesk

ответ

5

Вот метод, который должен работать очень хорошо, если все ваши элементов поиска фиксируются строки:

my %title_replacements = (
    ' PHD.' => ' PHD ', 
    ' P H D ' => ' PHD ', 
    # ..., 
); 

my $titles_to_replace = join '|', 
    map quotemeta, 
    keys %title_replacements; 

$titles_to_replace = qr/$titles_to_replace/; 

sub substitute_titles { 
    my ($in) = @_; 
    $$in =~ s/($titles_to_replace)/$title_replacements{$1}/g; 
} 

Если вы работаете на Perl старше 5,10 .0 или 5.8.9, вы должны подумать об использовании Regexp::Trie или Regexp::Assemble, чтобы создать регулярное выражение, но при текущих perls компилятор регулярных выражений автоматически оптимизирует любой большой список подобных изменений, поэтому я не учитывал ненужное усложнение.

5

Вместо того, запуская каждую замену отдельно, создать замыкание, которое может сделать для вас работу более эффективно:

sub make_translator { 
    my %table = @_; 
    my $regex = join '|' => map {quotemeta} keys %table; 
    $regex = qr/$regex/; 

    return sub {s/($regex)/$table{$1}/g} 
} 

my $translator = make_translator 
    ' PHD.' => ' PHD ', 
    ' P H D ' => ' PHD ', 
    ' PROF.' => ' PROF '; # ... the rest of the pairs 

my @list_of_strings = qw/.../; 

$translator->() for @list_of_strings; 

Это быстро, чтобы ничего не передать и использовать $_ псевдонимом со значением массива (который цикл for делает для вас).

0

Я, скорее всего, сделаю sub, который создал мои шаблоны для меня. Таким образом, все, что мне нужно сделать, это передать массив заголовков, которые я хочу нормализовать. Пример:

sub make_pattern { 
    my $list_ref = shift; 
    my %patterns; 
    for my $title (@{$list_ref}) { 
     my $result = uc $title; 
     my $pattern = '/' . join('\s*', (//, $title)) . '\.*/i'; 
     $patterns{$pattern} = $result; 
    } 
return \%patterns; 
} 

my @titles = qw (PHD MD DR PROF) #... plus whatever other titles you have 
my $conversion_hash = make_pattern(\@titles); 

Затем вы получаете хеш в сочетании с закрытием, как указано в некоторых других ответах здесь. Я еще не успел проверить свой код, но он должен работать.

Смежные вопросы