Каждый тип регулярного выражения, который я знаю, нумерует группы по порядку, в котором появляются открывающие скобки. То, что внешние группы нумеруются до того, как их подгруппы являются естественным результатом, а не явной политикой.
Интересно, где именованные группы . В большинстве случаев они следуют той же политике нумерации относительными позициями паренов - имя является просто псевдонимом для числа. Однако в регулярных выражениях .NET именованные группы нумеруются отдельно от нумерованных групп. Например:
Regex.Replace(@"one two three four",
@"(?<one>\w+) (\w+) (?<three>\w+) (\w+)",
@"$1 $2 $3 $4")
// result: "two four one three"
В действительности, число является псевдонимом для name ; номера, присвоенные именованным группам, начинаются там, где заканчиваются «реальные» пронумерованные группы. Это может показаться странной политикой, но для этого есть веская причина: в регулярных выражениях .NET вы можете использовать одно и то же имя группы в регулярном выражении несколько раз. Это делает возможным регулярные выражения, например, из этого потока для сопоставления чисел с плавающей запятой из разных локалей:
^[+-]?[0-9]{1,3}
(?:
(?:(?<thousand>\,)[0-9]{3})*
(?:(?<decimal>\.)[0-9]{2})?
|
(?:(?<thousand>\.)[0-9]{3})*
(?:(?<decimal>\,)[0-9]{2})?
|
[0-9]*
(?:(?<decimal>[\.\,])[0-9]{2})?
)$
Если есть разделитель тысяч, он будет сохранен в группе «тысяча» независимо от того, какая часть регулярного выражения соответствует ему. Аналогично, десятичный разделитель (если он есть) всегда будет сохранен в группе «десятичный». Конечно, есть способы идентифицировать и извлечь разделители без многократного использования именованных групп, но этот способ намного удобнее, я думаю, он более чем оправдывает странную схему нумерации.
А еще есть Perl 5.10+, который дает нам больший контроль над захватом групп, чем я знаю, что делать. : D