Как я могу ускорить свой Perl regex соответствие?

Мне нравится Правильный акроним BICEP от вышеупомянутого Прагматическое Поблочное тестирование книга:

  • Право : результаты право ?
  • B: действительно ли все эти корректные условия b oundary?
  • я : мы можем проверить я nverse отношения?
  • C: Можем мы результаты ross-проверки c с помощью других средств?
  • E: мы можем вызвать условия e rror произойти?
  • P: характеристики p erformance в границах?

Лично я чувствую, что можно стать довольно далекими путем проверки, что Вы добираетесь, правильные результаты (1+1 должен возвратиться 2 в дополнительной функции), испытывая все граничные условия, о которых можно думать (такие как использование, два числа которого сумма больше, чем целое число макс., оценивают в добавить функции), и вызывающий состояния ошибки, такие как отказы сети.

5
задан brian d foy 20 October 2009 в 05:22
поделиться

5 ответов

Трудно сказать, не увидев некоторых образцов данных.

Как правило, рекомендуется избегать использования . * . Поищите любые возможные источники ненужного поиска с возвратом и устраните их.

Вы можете обойтись разбиением со срезом, если ваши потребности просты.

 my @vals = (split / /, $string)[0,2,5,7];
7
ответ дан 18 December 2019 в 05:31
поделиться

Нет однозначного ответа на вопрос оптимизации регулярного выражения. Вы можете посмотреть, что делает конкретное регулярное выражение, с помощью прагмы re :

 use re 'debugcolor';

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

Вам также следует ознакомиться с Mastering Regular Expressions , где рассказывается, как работают регулярные выражения и почему некоторые шаблоны медленнее, чем другие.

19
ответ дан 18 December 2019 в 05:31
поделиться

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.

0
ответ дан 18 December 2019 в 05:31
поделиться

Это очень сильно зависит от профиля данных, которые вы сканируете.

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

Например, если только 5% вашей даты ввода содержало строку 'MV' , вы могли бы сначала отфильтровать это и применить полное более сложное регулярное выражение, только если более простое из них истинно .

Таким образом, у вас будет:

if ( $text_normal =~ / MV / ) {
  $text_normal = qr{^(\/F\d+) FF (.*?) SCF SF (.*?) MV (\(.*?)SH$};
  if .......
  }
}
6
ответ дан 18 December 2019 в 05:31
поделиться

(. *) означает, что вы имеете дело с любым количеством повторений «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».

2
ответ дан 18 December 2019 в 05:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: