Быстрая замена для Regex - PullRequest
       1

Быстрая замена для Regex

6 голосов
/ 20 января 2012

У меня в классе около 100 Regex вызовов, каждый вызов покрывает разные типы данных в текстовом протоколе, но у меня много файлов и на основе аналитики regex занимает 88% выполнения моего кода.

Многие код этого типа:

{
  Match m_said = Regex.Match(line, @"(.*) said,", RegexOptions.IgnoreCase);
  if (m_said.Success)
  {
    string playername = ma.Groups[1].Value;
    // some action
    return true;
  }
}

{
  Match ma = Regex.Match(line, @"(.*) is connected", RegexOptions.IgnoreCase);
  if (ma.Success)
  {
    string playername = ma.Groups[1].Value;
    // some action
    return true;
  }
}
{
  Match ma = Regex.Match(line, @"(.*): brings in for (.*)", RegexOptions.IgnoreCase);
  if (ma.Success)
  {
    string playername = ma.Groups[1].Value;
    long amount = Detect_Value(ma.Groups[2].Value, line);
    // some action
    return true;
  }
}

Можно ли заменить Regex каким-либо другим более быстрым решением?

Ответы [ 5 ]

8 голосов
/ 20 января 2012

Для регулярных выражений, которые тестируются в цикле, часто быстрее прекомпилировать их вне цикла и просто проверять их внутри цикла.

Вам необходимо сначала объявить различные регулярные выражения с соответствующими им шаблонами и вызвать только Match() с текстом для проверки на втором шаге.

3 голосов
/ 20 января 2012

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

(.*) is connected означает: сначала сопоставьте всю строку (это часть .*), затем верните один символ навремя, пока возможно совпадение is connected.

Теперь, если строка не очень короткая или is connected не появляется очень близко к концу строки, это большой возврат, который стоит времени.

Итак, если вы можете уточнить, что такое разрешенное совпадение, вы можете улучшить производительность.

Например, если разрешены только буквенно-цифровые символы, тогда (\w+) is connected будет хорошим.Если это какой-либо непробельный символ, используйте (\S+) is connected.И т.д., в зависимости от правил для действительного совпадения.

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

2 голосов
/ 20 января 2012

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

private static readonly Regex xmlRegex = new Regex("YOUR EXPRESSION", RegexOptions.Compiled);

В вашем примере каждый раз, когда метод используется, он «компилирует» выражение, но это не нужно, поскольку выражение является константой.Теперь он предварительно скомпилирован и скомпилирован только один раз.Недостатком является то, что при первом обращении к выражению оно работает немного медленнее.

1 голос
/ 20 января 2012

Я знаю, что Regex может многое, но вот тест с Regex против char.Split против string.split

http://www.dotnetperls.com/split в разделе Benchmarks

1 голос
/ 20 января 2012

Вы можете попробовать скомпилировать Regex заранее или рассмотреть возможность объединения всех отдельных выражений Regex в одно (монстр) Regex:

Match m_said = Regex.Match(line,
            @"(.*) (said|(is connected)|...|...),",
            RegexOptions.IgnoreCase);

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

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