эффективно тестировать EndsWith с помощью Regex - PullRequest
10 голосов
/ 17 января 2010

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

Код, который я пытаюсь исправить, использовал:

.*\.(png|jpg|gif)$

, что ужасно медленно длянеудачные совпадения в моем сценарии (предположительно из-за обратного отслеживания.

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

Мне все еще кажется, что он довольно неэффективен. Я что-то упускаю здесь очевидное?

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

Я также провел несколько тестов, используя RegexOptions.RightToLeft, и обнаружил, что с помощью * можно немного повысить производительность из моего тестового примера.1016 *, но я не могу найти способ указать параметр RightToLeft в строке самого регулярного выражения, поэтому не думаю, что смогу его использовать.

Ответы [ 5 ]

13 голосов
/ 17 января 2010

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

$(?<=\.(gif|png|jpg))

Однако я не уверен, какое влияние окажет прогноз на производительность.

6 голосов
/ 18 января 2010

На самом деле, вы также можете просто удалить Regex и использовать String.EndsWidth со следующим:

var extensions = new String[] { ".png", ".jpg", ".gif" };
extensions.Any(ext => "something".EndsWith(ext));

У меня обычно возникает ощущение, что в таких случаях быстрее получается использовать простые строковые функции, а не пытаться найти умный способ использования эффективного регулярного выражения с точки зрения времени выполнения и / или времени разработки, если только вы не комфортно и знаю, что эффективно с точки зрения Regex.

3 голосов
/ 17 января 2010

Сделайте так, чтобы он выглядел специально для периода вместо любого символа, предшествующего расширению:

\.(png|jpg|gif)$

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

2 голосов
/ 17 января 2010

Если вы можете изменить код, почему вы не можете использовать что-то еще? Вы не контролируете API, верно, но вы все равно меняете его. Это я действительно не понимаю.

В любом случае, почему бы просто:

var AcceptedExtensions = new List<string>() { "txt", "html", "htm" };
var extension = filename.Substring(filename.LastIndexOf(".") + 1).ToLower();
return AcceptedExtensions.Contains(extension);

IEnumerable AcceptedExtensions будет загружаться из некоторого конфига так же, как вы загружаете jpg|gif|.... Или это будет константа, что угодно. Вам просто не нужно создавать его заново каждый раз, когда вы собираетесь его использовать (я сомневаюсь, что это будет узким местом).

1 голос
/ 17 января 2010

Вам, вероятно, не нужно регулярное выражение для этого ... но, исходя из исходного вопроса:

Убедитесь, что вы используете RegexOptions.Compiled для предварительной компиляции регулярного выражения, а затем повторно используете ваш объект RegEx. Это позволяет избежать настройки RegEx каждый раз, когда вы его используете, это значительно ускорит процесс.

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