Эффективно тестировать EndsWith с помощью Regex
Мне нужно создать регулярное выражение (синтаксис.NET), чтобы определить, заканчивается ли строка определенным значением. В частности, мне нужно проверить, имеет ли файл конкретное расширение (или набор расширений).
Код, который я пытаюсь исправить, использовал:
.*\.(png|jpg|gif)$
что ужасно медленно для неудачных матчей в моем сценарии (вероятно, из-за возврата).
Просто удаляя .*
(что хорошо, поскольку API только проверяет совпадения и ничего не извлекает) в начале делает регулярное выражение гораздо более эффективным.
Это все еще чувствует, что это довольно неэффективно. Я что-то упускаю здесь очевидное?
К сожалению, я не контролирую API, о котором идет речь, поэтому для этого мне нужно регулярное выражение, хотя обычно я не считаю регулярное выражение подходящим инструментом для работы.
Я также сделал несколько тестов, используя RegexOptions.RightToLeft
и обнаружил, что я могу выжать немного больше производительности из моего теста с ^.*\.(png|jpg|gif)$
, но я не могу найти способ указать RightToLeft
вариант в строке самого регулярного выражения, поэтому я не думаю, что я могу его использовать.
5 ответов
У меня нет доступа к C#, поэтому я не могу попробовать это... но вы должны быть в состоянии избежать слишком большого возврата, заставив механизм сначала найти конец строки, а затем сопоставив расширения:
$(?<=\.(gif|png|jpg))
Однако я не уверен в том, какое влияние оказывает прогнозирование на производительность.
На самом деле, вы также можете просто отказаться от Regex и использовать String.EndsWidth
со следующим:
var extensions = new String[] { ".png", ".jpg", ".gif" };
extensions.Any(ext => "something".EndsWith(ext));
У меня обычно возникает ощущение, что в таких случаях быстрее использовать простые строковые функции, а не пытаться найти умный способ использования эффективного регулярного выражения с точки зрения времени выполнения и / или времени разработки, если вы не знакомы с знать, что эффективно с точки зрения Regex.
Сделайте так, чтобы он выглядел специально для точки вместо любого символа, предшествующего расширению:
\.(png|jpg|gif)$
Это сделает его более безопасным (не будет соответствовать x.xgif), и ему не нужно будет выполнять какой-либо возврат, пока он не найдет точку (в отличие от возврата для каждого персонажа).
Если вы можете изменить код, почему вы не можете использовать что-то еще? Вы не управляете 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|...
, Или это будет константа, что угодно. Вам просто не нужно воссоздавать его каждый раз, когда вы собираетесь его использовать (я сомневаюсь, что это будет узким местом, хотя).
Вы, вероятно, не нуждаетесь в регулярном выражении для этого... но перейдем к исходному вопросу:
Убедитесь, что вы используете RegexOptions.Compiled для предварительной компиляции регулярного выражения, а затем повторно используете ваш объект RegEx. Это позволяет избежать настройки RegEx каждый раз, когда вы его используете, это значительно ускорит процесс.