Мне нравится Правильный акроним BICEP от вышеупомянутого Прагматическое Поблочное тестирование книга:
Лично я чувствую, что можно стать довольно далекими путем проверки, что Вы добираетесь, правильные результаты (1+1 должен возвратиться 2 в дополнительной функции), испытывая все граничные условия, о которых можно думать (такие как использование, два числа которого сумма больше, чем целое число макс., оценивают в добавить функции), и вызывающий состояния ошибки, такие как отказы сети.
Трудно сказать, не увидев некоторых образцов данных.
Как правило, рекомендуется избегать использования . *
. Поищите любые возможные источники ненужного поиска с возвратом и устраните их.
Вы можете обойтись разбиением
со срезом, если ваши потребности просты.
my @vals = (split / /, $string)[0,2,5,7];
Нет однозначного ответа на вопрос оптимизации регулярного выражения. Вы можете посмотреть, что делает конкретное регулярное выражение, с помощью прагмы re :
use re 'debugcolor';
. Как только вы увидите, что оно проходит по строке, вы увидите, где возникают проблемы, и измените свое регулярное выражение оттуда. По мере того, как вы это делаете, вы узнаете немного о механизме регулярных выражений.
Вам также следует ознакомиться с Mastering Regular Expressions , где рассказывается, как работают регулярные выражения и почему некоторые шаблоны медленнее, чем другие.
Backtracking is one of the surest ways to kill regex performance, but, unfortunately, this does not appear to be a case where you're able to completely eliminate the .
wildcard in favor of character classes, unless the text you're capturing is prohibited from containing uppercase characters. (If that prohibition does exist, you could replace your .*?
with, say, [a-z ]*
instead.)
You can still reduce the possibility for backtracking by using {}
to set a minimum/maximum number of characters to match, such as .{0,10}?
if the match can't be longer than 10 characters.
Это очень сильно зависит от профиля данных, которые вы сканируете.
Вы определяете часть своего регулярного выражения, которое фильтрует большую часть входных данных, и делаете для этого отдельное более простое регулярное выражение. выражение.
Например, если только 5% вашей даты ввода содержало строку 'MV'
, вы могли бы сначала отфильтровать это и применить полное более сложное регулярное выражение, только если более простое из них истинно .
Таким образом, у вас будет:
if ( $text_normal =~ / MV / ) {
$text_normal = qr{^(\/F\d+) FF (.*?) SCF SF (.*?) MV (\(.*?)SH$};
if .......
}
}
(. *)
означает, что вы имеете дело с любым количеством повторений «SCF SF», прежде чем найдете то, которое указывает, что это следующий захват. Делая его нежадным, вы по-прежнему поддерживаете возможность того, что даже «SCF SF» появится в захвате после «FF». Я думаю, что вы обрабатываете множество случаев, которые вам не нужны.
Лучший способ оптимизировать регулярное выражение иногда делает его более загадочным, но вы определенно найдете способы заставить выражение выйти из строя раньше . (. *?)
, хотя и не является «жадным», определенно слишком терпим.
Ниже представлена более подробная, но более быстрая альтернатива вашему второму захвату.
((?:[^S]|S[^C]|SC[^F]|SCF[^ ]|SCF [^S]|SCF S[^F])*)
Но вы можете оптимизировать его еще больше, если считаете, что строка \ bSCF \ b
должна автоматически выполнять фиксацию захвата и ожидать только "\ bSCF SF \ b". Таким образом, вы можете переписать это как:
((?:[^S]|S[^C]|SC[^F]SCF\B)*) SCF SF
Но вы можете еще больше оптимизировать эти строки, используя управление с возвратом. Если вы думаете, что в мире нет способа, чтобы SCF когда-либо встречался как слово и не сопровождался SF при правильном вводе. Для этого вы добавляете к нему еще одну группу с квадратными скобками (?>
и )
.
(?>((?:[^S]|S[^C]|SC[^F]SCF\B)*)) SCF SF
Это означает, что логика сопоставления никоим образом не будет пытаться переоценить то, что она захватила. . Если символы после этого не могут быть "SCF SF", все выражение не выполняется. И он терпит неудачу задолго до того, как он когда-либо пытается приспособить "MV" и другие подвыражения.
Фактически, учитывая определенные выражения об уникальности разделителей, самая быстрая производительность для этого выражения будет:
$text_normal = qr{^(\/F\d+) FF (?>((?:[^S]|S[^C]|SC[^F]SCF\B)*))SCF SF (?>((?:[^M]|M[^V]|MV\B)*))MV (?>(\((?:[^S]|S[^H]|SH.)*))SH$};
Кроме того, подробные, исчерпывающие отрицательные совпадения могут быть альтернативно выражены отрицательными опережающими взглядами - но я понятия не имею, как это влияет на производительность . Но отрицательный просмотр вперед будет работать следующим образом:
((?:.(?! SCF))*) SCF SF
Это означает, что для этого захвата мне нужен любой символ, кроме пробела, начинающего строку «SCF SF».