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