Есть предложения по улучшению (оптимизации) существующей подстановки строк в Perl-коде?


Perl 5.8

Улучшения для довольно простых замен строк в существующем скрипте Perl.
Цель кода ясна, и код работает.

Для данной строки замените каждое вхождение символа TAB, LF или CR одним пробелом и замените каждое вхождение двойной кавычки двумя двойными кавычками. Вот фрагмент из существующего кода:


# replace all tab, newline and return characters with single space
$val01  =~s/[tnr]/ /g;
$val02  =~s/[tnr]/ /g;
$val03  =~s/[tnr]/ /g;

# escape all double quote characters by replacing with two double quotes
$val01  =~s/"/""/g;
$val02  =~s/"/""/g;
$val03  =~s/"/""/g;

Вопрос: Есть ли лучший способ выполнить эти строки манипуляции?

Под "лучшим способом" я подразумеваю более эффективное их выполнение, избегая использования регулярных выражений (возможно, используя tr/// для замены символов tab, newline и lf), или, возможно, используя using (qr//), чтобы избежать перекомпиляции.

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

Примечание: этот код работает, он на самом деле не сломан. Я просто хочу знать, есть ли еще соответствующая конвенция о кодировании.

Примечание: эти операции выполняются в цикле, большом числе (>10000) итераций.

Примечание: этот скрипт в настоящее время выполняется под perl v5.8.8. (В скрипте есть require 5.6.0, но его можно изменить на require 5.8.8. (Установка более поздней версии Perl в настоящее время не является опцией на рабочем сервере.)


    > perl -v
    This is perl, v5.8.8 built for sun4-solaris-thread-multi
    (with 33 registered patches, see perl -V for more detail)
4 4

4 ответа:

Ваше существующее решение кажется мне прекрасным.

Что касается того, чтобы избежать перекомпиляции, вам не нужно беспокоиться об этом. Регулярные выражения Perl компилируются только один раз, если только они не содержат интерполированных выражений, чего нет у вас.

Для полноты картины я должен упомянуть, что даже если интерполированные выражения присутствуют, Вы можете попросить Perl скомпилировать регулярное выражение только один раз, поставив флаг /o.
$var =~ s/foo/bar/;    # compiles once
$var =~ s/$foo/bar/;   # compiles each time
$var =~ s/$foo/bar/o;  # compiles once, using the value $foo has
                       # the first time the expression is evaluated

TMTOWTDI

В качестве альтернативы можно использовать функции tr или index, substr или split. Но вы должны сделать измерения, чтобы определить наилучший метод для вашей конкретной системы.

Возможно, вы преждевременно оптимизируетесь. Вы пробовали использовать профилировщик, такой как Devel:: NYTProf, чтобы увидеть, где ваша программа проводит большую часть своего времени?

Я предполагаю, что tr/// будет (немного) быстрее, чем s/// в вашем первом регулярном выражении. Насколько быстрее, конечно, будет зависеть от факторов, которые я не знаю о вашей программе и вашей среде. Профилирование и сравнительный анализ дадут ответ на этот вопрос.

Но если вы заинтересованы в каком-либо улучшении вашего кода, могу ли я Предложить исправление ремонтопригодности? Вы выполняете одну и ту же подстановку (или набор подстановок) для трех переменных. Это означает, что когда вы измените это замена, вам нужно изменить его три раза - и делать то же самое три раза всегда опасно:)

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

foreach ($val01, $val02, $val03) {
    s/[\t\n\r]/ /g;
    s/"/""/g;
}

Кроме того, было бы, вероятно, хорошей идеей иметь эти значения в массиве, а не три таких же одноименных переменных.

foreach (@vals) {
    s/[\t\n\r]/ /g;
    s/"/""/g;
}