2013-12-26 3 views
3

Вот выдержка из моего кода:RegularExpressions.Regex.IsMatch висит

string[] myStr = 
     { 
      " Line1: active 56:09 - tst0063, tst0063", 
      "Contacts accosiated with line 1 - tst0063, tst0063", 
      "Line 1: 00:00:32  Wrap: 00:00:20 - tst0063, tst0063", 
      "Line 1: 00:00:17  Active: 00:00:15 - tst0064, tst0064" 
     }; 

string sPattern = @"^Line(\s*\S*)*tst0063$"; 
RegexOptions options = RegexOptions.IgnoreCase; 

foreach (string s in myStr) 
{ 
    System.Console.Write(s); 

    if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern, options)) 
    { 
     System.Console.WriteLine(" - valid"); 
    } 
    else 
    { 
     System.Console.WriteLine(" - invalid"); 
    } 
    System.Console.ReadLine(); 
} 

RegularExpressions.Regex.IsMatch зависает во время работы на последней строке. Я сделал несколько экспериментов, но до сих пор не могу понять, почему он висит, когда нет конца в конце строки. Пожалуйста помоги!

+2

Как насчет использования этого шаблона? '^ Линия [\ s * \ S *] * tst0063 $' С Рождеством! –

+0

Отредактировано: 4 линии вместо 2 как ответ на ответ ниже. – Lola

+0

Итак, с 4 строками, он не зависает на второй строке ... он всегда зависает на линии _last_? –

ответ

3

Вопрос не в том, почему четвертый тест висит, но почему первые три не делают. Первая строка начинается с пробела, а вторая начинается с Contacts, ни одна из которых не соответствует регулярному выражению ^Line, поэтому первые две попытки совпадения не срабатывают немедленно. Третья строка соответствует регулярному выражению; хотя для этого требуется гораздо больше времени (по причинам, которые я собираюсь объяснить), это все еще кажется мгновенным.

Четвертое совпадение не выполняется, потому что строка не совпадает с конечной частью регулярного выражения: tst0063$. Когда это не удается, двигатель регулярных выражений возвращается к переменной части регулярного выражения, (\s*\S*)* и начинает пытаться использовать всевозможные способы, чтобы соответствовать этой строке. В отличие от третьей строки, на этот раз она должна попробовать каждую возможную комбинацию нулевых или более пробельных символов (\s*), за которыми следуют ноль или несколько символов без пробелов (\S*), ноль или более раз, прежде чем он сможет отказаться. Возможности не бесконечны, но они также могут быть.

Возможно, вы, вероятно, думали о [\s\S]*, что является известной идиомой для соответствия любому персонажу , включая символы новой строки. Он используется в JavaScript, который не имеет способа сделать точку (.) символами разделителя строк линии. Большинство других ароматов позволяют указать режим соответствия, который изменяет поведение точки; некоторые называют его DOTALL режиме, но .NET использует более распространенный Singleline.

string sPattern = @"^Line.*tst0063$"; 
RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Singleline; 

Вы можете также использовать рядный модификаторы:

string sPattern = @"(?is)^Line.*tst0063$"; 

UPDATE: В ответ на ваш комментарий, да, это действительно кажется странным, что движок регулярных выражений не может сказать, что любой матч must конец с tst0063. Но это не всегда так легко сказать. Сколько усилий нужно было искать в таких ярлыках? И сколько ярлыков вы можете использовать для нормального алгоритма соответствия до все совпадений (успешно и неудачно) становятся слишком медленными?

У .NET есть одна из лучших реализаций регулярных выражений: быстрая, мощная и с некоторыми действительно удивительными функциями. Но вы должны думать о том, что вы говорите. Например, если вы знаете, что должен быть хотя бы один из них, используйте +, а не *. Если бы вы следовали этому правилу, у вас не было бы этой проблемы. Данное регулярное выражение:

@"^Line(\s+\S+)*tst0063$" 

... работает просто отлично.(\s+\S+)* - вполне разумный способ совместить ноль или более слов, где слова определяются как один или несколько символов без пробелов, отделенных от других слов одним или несколькими символами пробелов. (Это то, что вы пытались сделать?)

+1

Спасибо! Но почему он поддерживает 4-ю строку? Конечная часть не соответствует, не следует ли просто сообщать о сбое и выйти? – Lola

2

Перемещение System.Console.ReadLine(); за пределами foreach петля.

Вы блокируете поток в конце первой итерации цикла, ожидая ввода пользователя.

+0

У меня тот же результат (висит на последней строке, которая имеет несоответствующий конец), даже у меня есть более двух строк. Кроме того, когда я его отлаживаю, я вижу, что он висит под IsMatch(). – Lola