.NET Regex Negative Lookahead – что я делаю неправильно?

Предполагая, что у меня есть:

StartTest NoInclude EndTest StartTest Include EndTest 

и я использую:

 /StartTest(?!NoInclude)[\s\S]*?EndTest/g 

Почему я сопоставляю обе группы?

Пример Regexr: http://regexr.com/3db8m

Вы не выполняете матч с помощью NoInclude если NoInclude появляется сразу после StartTest . Вам нужен умеренный жадный токен :

 (?s)StartTest(?:(?!(?:Start|End)Test|NoInclude).)*EndTest ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

См. Демо-версию regex

StartTest выражение соответствует StartTest , затем соответствует любому тексту, который не является StartTest , EndTest или NoInclude , вплоть до EndTest .

Потому что * жадный, он сделает . как можно больше. Отрицательный outlook заставит его прекратить сопоставление в местах, где следуют следующие альтернативы:

  • (?:Start|End)TestStartTest или EndTest
  • NoInclude – просто NoInclude .

ПРИМЕЧАНИЕ . (?s) является встроенным модификатором (эквивалентом флага RegexOptions.Singleline ), который модифицирует . поведение в шаблоне, что также соответствует LF (новые строки). Без этого модификатора (или без RegexOptions.Singleline ) точка соответствует любому символу, но новой RegexOptions.Singleline .

ПРИМЕЧАНИЕ 2. Если вы тестируете регулярное выражение вне среды исходного кода, убедитесь, что вы используете соответствующий тестер для вашего аромата регулярного выражения. regexr.com поддерживает только JavaScript-вкус, regex101.com поддерживает JS, PCRE и Python, а также поддерживает RegexStorm.net/RegexHero.net. Есть еще много тестировщиков, читайте, что они поддерживают, а что не первое.

Вот демонстрация C # :

 using System; using System.IO; using System.Text.RegularExpressions; using System.Linq; public class Test { public static void Main() { var input = "StartTest\n NoInclude\nEndTest\n\nStartTest\n Include\nEndTest"; var regex = new Regex(@"(?s)StartTest(?:(?!(?:Start|End)Test|NoInclude).)*EndTest"); var results = regex.Matches(input).Cast() .Select(p => p.Value) .ToList(); Console.WriteLine(string.Join("\n", results)); } }