2010-03-07 2 views
10

Я думал, что по умолчанию моего Regex будет проявлять жадное поведение, что я хочу, но это не в следующем коде:Regex ведет себя ленивым, должно быть жадным

Regex keywords = new Regex(@"in|int|into|internal|interface"); 
var targets = keywords.ToString().Split('|'); 
foreach (string t in targets) 
    { 
    Match match = keywords.Match(t); 
    Console.WriteLine("Matched {0,-9} with {1}", t, match.Value); 
    } 

Выход:

Matched in  with in 
Matched int  with in 
Matched into  with in 
Matched internal with in 
Matched interface with in 

Теперь я понимаю, что я мог заставить его работать на этом маленьком примере, если я просто сортировал ключевые слова по длине по убыванию, но

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

Итак, мой вопрос: почему это лениво и как его исправить?

+0

Я не уверен, что ваше фактическое использование является более сложным, но если приведенный выше пример - это то, что вы делаете, я думаю, что вы будете в тысячу раз лучше, зациклившись на вашем списке слов, ищущих совпадения с методом IndexOf , Если регулярное выражение просто содержит кучу слов в чередовании, производительность, вероятно, будет сосать. – Josh

+0

@ Josh - Нет, пример упрощен. Фактическое приложение - это чтение языковых файлов для генерации лексеров и грамматических парсеров. Я просто немного ржавый в своих регулярных выражениях; моя проблема кажется такой очевидной сейчас! – Stomp

+0

@Josh: Двигатели Regex могут делать много оптимизаций для таких случаев, включая отбрасывание многих проверок после отказа от общего префикса. Например, если первый символ не является «i», ни одна из ветвей, начинающихся с «i», не будет проверена. Не уверен, что движок .NET делает это, но я был бы удивлен, если бы это не так. –

ответ

12

лени и прожорливость относятся только к квантификаторам (?, *, +, {min,max}). Чередования всегда совпадают по порядку и пробуют первое возможное совпадение.

+0

+1, должны быть кванторы для жадности. – codaddict

+0

Нет параметров, кроме повторного заказа? Hrmmm ... Думаю, я мог бы переупорядочить его на лету, чтобы я мог сохранить определение в алфавитном порядке ... – Stomp

+0

@Stomp: Да, это можно сделать. Сохраните список в алфавитном порядке в программе, и перед тем, как вы его примените, вы можете отсортировать его по длине. – codaddict

3

Согласно RegularExpressions.info, регулярные выражения: eager. Поэтому, когда он проходит через ваш piped expression, он останавливается на первом сплошном матче.

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

+0

@Jeras - Спасибо за ссылки! Я искал MSDN и, должно быть, пропустил, что он с нетерпением ждал первого матча. – Stomp

6

Похоже, вы пытаетесь сломать вещи. Для этого вам нужно, чтобы все выражение было правильным, ваше текущее - нет. Попробуйте это вместо ..

new Regex(@"\b(in|int|into|internal|interface)\b"); 

«\ Ъ» говорит, чтобы соответствовать границам слов, и нулевой шириной матч. Это поведение зависит от локали, но в целом это означает пробелы и пунктуации. Будучи совпадением с нулевой шириной, он не будет содержать символ, который заставил механизм регулярных выражений обнаружить границу слова.

+1

Добавление '\ b' приведет к желаемому поведению, но вы ошибаетесь в том, как оно работает. '\ b' - это утверждение с нулевой шириной, как'^',' $ 'и lookarounds; вместо сопоставления символа он соответствует воображаемому разрыву * до или после символа. Начало или конец строки автоматически является границей слов, если первый или последний символ (соответственно) является символом слова, поэтому ваше второе регулярное выражение является только более подробной версией первой. –

+0

@Alan, я попробовал выполнить код, и, разумеется, вы правы. Мне нужно будет дважды проверить код на работе, чтобы посмотреть, что мы там делаем ... Возможно, мы используем \ W, а не \ b. Я знаю, что мы получали какие-то «не-словные» персонажи в подобной ситуации, когда я знаю, что у нас были какие-то фанковые группы регистрации зондов. Что касается языковой чувствительности, это будет иметь место, поскольку границы слов будут определены по-разному на основе роли пунктуации. –

+0

@Alan, я внесла свой ответ, чтобы отразить ваши отзывы. –