Регулярное выражение.Matches возвращает по одному совпадению в строке, а не в «слове»

#c# #.net #regex

#c# #.net #регулярное выражение

Вопрос:

Мне трудно понять, почему следующее выражение \[B. \] и код возвращают количество совпадений, равное 1:

 string r = "\[B. \]";
return Regex.Matches(Markup, sRegEx);
  

Я хочу найти все экземпляры (назовем их «тегами») (в разметке HTML-строки переменной длины, которая не содержит разрывов строк), которые имеют префикс B и заключены в квадратные скобки.

Если разметка содержит [BName] , я получаю одно совпадение — хорошее.

Если разметка содержит [BName] [BAddress] , я получаю одно совпадение — почему?

Если разметка содержит [BName][BAddress] , я также получаю только одно совпадение.

В некоторых веб-тестерах регулярных выражений я заметил, что если текст содержит символ CR, я получу совпадение в строке — но мне нужен какой-то способ указать, что я хочу, чтобы совпадения возвращались независимо от разрывов строк.

Я также покопался в группах и захватил коллекции MatchCollection, но безрезультатно — всегда только один результат.

Ответ №1:

Вы получаете только одно совпадение, потому что по умолчанию регулярные выражения .NET «жадные»; они пытаются сопоставить как можно больше с помощью одного совпадения.

Поэтому, если ваше значение равно [BName][BAddress] , у вас будет одно совпадение — которое будет соответствовать всей строке; таким образом, оно будет совпадать с [B начала вплоть до последнего ] — вместо первого. Если вам нужны два совпадения, используйте вместо этого этот шаблон: \[B. ?\]

? После указывает поисковому механизму, чтобы он соответствовал как можно меньше… оставляя вторую группу для ее собственного совпадения.

Slaks также отметил отличный вариант; конкретно указав, что вы не хотите сопоставлять окончание ] как часть содержимого, вот так: \[B[^\]] \] Это делает ваше совпадение «жадным», что может быть полезно в каком-то другом случае. В этом конкретном случае может быть не так много различий, но это важно иметь в виду в зависимости от того, с какими данными / шаблонами вы можете иметь дело конкретно.


Кстати, я рекомендую использовать спецификатор C # «literal string» @ для шаблонов регулярных выражений, чтобы вам не нужно было дважды экранировать что-либо в шаблонах регулярных выражений; Поэтому я бы установил шаблон следующим образом:

 string pattern = @"[B. ?]";
  

Это значительно упрощает вычисление более сложных регулярных выражений

Комментарии:

1. Потрясающе — быстрое, хорошо написанное и даже включающее несколько дополнительных советов! Большое спасибо.

Ответ №2:

Попробуйте вместо этого использовать строку регулярного выражения \[B. ?\] . . само по себе (то же самое в значительной степени верно для .* ) будет соответствовать максимально возможному количеству символов, тогда как . ? (или .*? ) будет соответствовать минимальному количеству символов, все еще удовлетворяя остальной части выражения.

Комментарии:

1. 1 за то, что также упомянул, что ? модификатор квантора также может быть использован против * при использовании в качестве квантора. Хотите верьте, хотите нет, но это также можно использовать против ? . Просто обратите внимание, что с помощью * и ? он попытается сопоставить 0 раз, если это возможно. Иногда это может привести к кажущимся странными результатам.

Ответ №3:

. это жадное совпадение; оно будет соответствовать как можно большему количеству.
Во втором примере оно совпадает BName] [BAddress .

Вы должны написать [B[^]] ] .
[^]] совпадает со всеми символами, кроме ] , поэтому он вынужден останавливаться перед первым ] .

Комментарии:

1. 1 ; это вполне может быть лучшим вариантом, чем тот, который я изначально опубликовал, в зависимости от рассматриваемых данных. Возможно, в этом случае это не имеет значения, но, вероятно, лучше в общем случае сопоставления чего-то, что выглядит как ‘tag’. Я добавил это (с атрибуцией) к своему ответу.