Почему этот цикл через группы Regex печатает результат дважды?
Я написал этот очень прямой код регулярного выражения
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace RegexTest1
{
class Program
{
static void Main(string[] args)
{
string a = "\"foobar123==\"";
Regex r = new Regex("^\"(.*)\"$");
Match m = r.Match(a);
if (m.Success)
{
foreach (Group g in m.Groups)
{
Console.WriteLine(g.Index);
Console.WriteLine(g.Value);
}
}
}
}
}
Однако вывод
0
"foobar123=="
1
foobar123==
Я не понимаю, почему он печатает дважды. почему должен быть захват с индексом 0? когда я говорю в своем регулярном выражении ^\"
, и я не использую для этого захват.
Извините, если это очень просто, но я не пишу Regex на ежедневной основе.
По мне, этот код должен печатать только один раз, а индекс должен быть 1, а значение должно быть foobar ==
Ответы
Ответ 1
Это происходит потому, что группа ноль является специальной: она возвращает все совпадение.
Из Документация по регулярному выражению (выделено мной):
Простой шаблон регулярного выражения иллюстрирует, как пронумерованные (неназванные) и именованные группы могут ссылаться либо программно, либо с помощью синтаксиса языка выражения. Регулярное выражение ((?<One>abc)\d+)?(?<Two>xyz)(.*)
создает следующие группы захвата по числу и по имени. Первая группа захвата (число 0) всегда ссылается на весь шаблон.
# Name Group
- ---------------- --------------------------------
0 0 (default name) ((?<One>abc)\d+)?(?<Two>xyz)(.*)
1 1 (default name) ((?<One>abc)\d+)
2 2 (default name) (.*)
3 One (?<One>abc)
4 Two (?<Two>xyz)
Если вы не хотите его видеть, запустите вывод из первой группы.
Ответ 2
Регулярное выражение захватывает сразу несколько групп. Группа 0
- это вся согласованная область (включая акценты). Группа 1
- это группа, определенная скобками.
Скажите, что ваше регулярное выражение имеет следующую форму:
A(B(C)D)E.
С выражениями A
, B
, C
, D
end E
regex.
Затем будут сопоставлены следующие группы:
0 A(B(C)D)E
1 B(C)D
2 C
i
-я группа начинается с i
-й открытой скобки. И вы можете сказать, что "нулевая" открытая скобка неявно помещается в начало регулярного выражения (и заканчивается в конце регулярного выражения).
Если вы хотите опустить группу 0
, вы можете использовать метод Skip
структуры LINQ:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace RegexTest1 {
class Program {
static void Main(string[] args) {
string a = "\"foobar123==\"";
Regex r = new Regex("^\"(.*)\"$");
Match m = r.Match(a);
if (m.Success) {
foreach (Group g in m.Groups.Skip(1)) {//Skipping the first (thus group 0)
Console.WriteLine(g.Index);
Console.WriteLine(g.Value);
}
}
}
}
}
Ответ 3
0
"foobar123==" -- Matched string.
Полное совпадение по шаблону будет найдено в индексе 0.
1
foobar123== -- Captured string.
Групповой индекс 1 содержит символы, которые захватываются первой группой .
Ответ 4
Использование регулярного выражения @dasblinkenlight в качестве примера...
Это не вся история с подсчетом группы захвата Dot-Net.
По мере добавления названных групп значение по умолчанию подсчитывается и считается последним.
Они могут быть изменены.
Конечно, группа 0 всегда содержит весь матч. Групповой подсчет действительно начинается с 1
потому что вы не можете указать обратную ссылку (в регулярном выражении) группе 0, она конфликтует с
с двоичной конструкцией \0000
.
Здесь подсчитывается с именованными/нормальными группами в Dot-Net состояние по умолчанию.
( # (1 start)
(?<One> abc ) #_(3)
\d+
)? # (1 end)
(?<Two> xyz ) #_(4)
( .* ) # (2)
Здесь с последними именами отключены.
( # (1 start)
(?<One> abc ) # (2)
\d+
)? # (1 end)
(?<Two> xyz ) # (3)
( .* ) # (4)
Здесь, когда именованный счетчик выключен.
( # (1 start)
(?<One> abc )
\d+
)? # (1 end)
(?<Two> xyz )
( .* ) # (2)
Ответ 5
Вы можете вернуть только один, удалив группу 1 с помощью ?:
Regex r = new Regex("^\"(?:.*)\"$");
Онлайн-демонстрация
Каждый раз, когда вы используете ()
, вы создаете группы, и вы можете ссылаться на них позже, используя обратные ссылки $1, $2, $3, конечно, в случае вашего выражения проще:
Regex r = new Regex("^\".*\"$");
Что не использует скобки вообще