Перейти к содержимому

66. Regex Groups

![Иллюстрация к уроку](/lessons/javascript-regex-groups.png)
Regex groups (группы регулярных выражений) позволяют извлекать конкретные части совпадающей строки. Это мощный инструмент для разбора и обработки текста. В этом уроке мы разберемся, как их использовать.
## Что такое Regex Groups?
Regex Groups — это способ выделить отдельные части шаблона регулярного выражения, чтобы потом их использовать. Они определяются с помощью круглых скобок `( )`. Когда регулярное выражение с группами применяется к строке, движок regex запоминает части строки, которые соответствуют каждой группе.
### Пример 1: Простое извлечение имени и фамилии
Допустим, у нас есть строка с именем и фамилией, разделенными пробелом, и мы хотим извлечь имя и фамилию отдельно.
```javascript
const nameString = "Иван Иванов";
const regex = /(\w+)\s(\w+)/; // Первая группа: имя, вторая группа: фамилия
const match = nameString.match(regex);
if (match) {
const firstName = match[1]; // Индекс 0 - вся строка, 1 - первая группа
const lastName = match[2]; // 2 - вторая группа
console.log("Имя:", firstName); // Вывод: Имя: Иван
console.log("Фамилия:", lastName); // Вывод: Фамилия: Иванов
}

В этом примере (\w+) соответствует одному или нескольким буквенным символам (имя или фамилия), а \s соответствует пробелу. match[1] содержит текст, соответствующий первой группе (имя), а match[2] — текст, соответствующий второй группе (фамилия).

Предположим, у нас есть дата в формате YYYY-MM-DD, и мы хотим извлечь год, месяц и день.

const dateString = "2023-10-26";
const regex = /(\d{4})-(\d{2})-(\d{2})/; // Группы: год, месяц, день
const match = dateString.match(regex);
if (match) {
const year = match[1];
const month = match[2];
const day = match[3];
console.log("Год:", year); // Вывод: Год: 2023
console.log("Месяц:", month); // Вывод: Месяц: 10
console.log("День:", day); // Вывод: День: 26
}

Здесь \d{4} соответствует четырем цифрам (год), \d{2} соответствует двум цифрам (месяц и день).

Пример 3: Использование Named Capture Groups (именованные группы захвата)

Заголовок раздела «Пример 3: Использование Named Capture Groups (именованные группы захвата)»

Начиная с ES2018, можно давать группам имена, что делает код более читаемым.

const dateString = "2023-10-26";
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = dateString.match(regex);
if (match) {
const year = match.groups.year;
const month = match.groups.month;
const day = match.groups.day;
console.log("Год:", year); // Вывод: Год: 2023
console.log("Месяц:", month); // Вывод: Месяц: 10
console.log("День:", day); // Вывод: День: 26
}

В этом примере (?<year>\d{4}) дает группе имя “year”. Доступ к захваченным значениям осуществляется через match.groups.year.

Regex Groups часто используются в парсинге URL-адресов. Например, можно извлечь протокол, домен и путь из URL.

const url = "https://www.example.com/path/to/page";
const regex = /(?<protocol>\w+):\/\/(?<domain>[\w.]+)\/(?<path>.*)/;
const match = url.match(regex);
if (match) {
const protocol = match.groups.protocol;
const domain = match.groups.domain;
const path = match.groups.path;
console.log("Протокол:", protocol); // Вывод: Протокол: https
console.log("Домен:", domain); // Вывод: Домен: www.example.com
console.log("Путь:", path); // Вывод: Путь: path/to/page
}

Фреймворки, такие как React и Angular, используют регулярные выражения для маршрутизации, где группы используются для извлечения параметров из URL-адреса. Например, адрес /users/123 можно разобрать, чтобы получить ID пользователя (123).

  • Группы определяются круглыми скобками ( ).
  • Доступ к группам осуществляется через индексы в массиве match, начиная с 1 (0 - вся строка).
  • Именованные группы захвата (Named Capture Groups) ((?<name>...)) делают код более читаемым.
  • Regex Groups полезны для извлечения и обработки частей текста.
  • Используются в парсинге URL, маршрутизации и других задачах обработки текста.
## Интерактивный пример
<Playground client:load
template="static"
files={{
"/index.html": `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body { background: #1e1e2e; color: #cdd6f4; font-family: sans-serif; padding: 16px; margin: 0; }
button { background: #89b4fa; color: #1e1e2e; border: none; padding: 7px 14px; border-radius: 6px; cursor: pointer; margin: 3px; font-size: 13px; font-weight: 600; }
button:hover { background: #74c7ec; }
.box { background: #313244; border-radius: 8px; padding: 14px; margin: 8px 0; }
.out { background: #181825; border-radius: 6px; padding: 10px; font-family: monospace; font-size: 12px; min-height: 100px; color: #a6e3a1; white-space: pre-wrap; }
h3 { color: #cba6f7; margin: 0 0 10px; font-size: 14px; }
input { background: #313244; color: #cdd6f4; border: 1px solid #45475a; padding: 5px 8px; border-radius: 4px; font-size: 13px; width: 260px; margin-bottom: 6px; display: block; }
label { font-size: 12px; color: #a6adc8; display: block; margin-bottom: 2px; }
</style>
</head>
<body>
<div class="box">
<h3>Тестер групп в регулярных выражениях</h3>
<label>Строка для теста:</label>
<input id="text" value="2024-03-15">
<label>Паттерн (без //):</label>
<input id="pattern" value="(\d{4})-(\d{2})-(\d{2})">
<label>Именованный паттерн:</label>
<input id="named" value="(?&lt;year&gt;\d{4})-(?&lt;month&gt;\d{2})-(?&lt;day&gt;\d{2})">
<button onclick="testGroups()">Тест групп</button>
<button onclick="testNamed()">Тест именованных групп</button>
</div>
<div class="out" id="out">Введите строку и паттерн, нажмите кнопку...</div>
<script>
var out = document.getElementById('out');
window.testGroups = function() {
var text = document.getElementById('text').value;
var pat = document.getElementById('pattern').value;
try {
var re = new RegExp(pat);
var m = text.match(re);
if (!m) { out.textContent = 'Нет совпадений для: /' + pat + '/'; return; }
var lines = ['Строка: "' + text + '"', 'Паттерн: /' + pat + '/', '', 'Результат:'];
lines.push(' match[0] (вся строка): "' + m[0] + '"');
for (var i = 1; i < m.length; i++) lines.push(' match[' + i + '] (группа ' + i + '): "' + m[i] + '"');
out.textContent = lines.join('\\n');
} catch(e) { out.textContent = 'Ошибка в паттерне: ' + e.message; }
}
window.testNamed = function() {
var text = document.getElementById('text').value;
var pat = document.getElementById('named').value;
try {
var re = new RegExp(pat);
var m = text.match(re);
if (!m) { out.textContent = 'Нет совпадений'; return; }
var lines = ['Строка: "' + text + '"', 'Паттерн: /' + pat + '/', '', 'Именованные группы (match.groups):'];
if (m.groups) {
Object.keys(m.groups).forEach(function(k) { lines.push(' ' + k + ': "' + m.groups[k] + '"'); });
} else { lines.push(' (нет именованных групп)'); }
out.textContent = lines.join('\\n');
} catch(e) { out.textContent = 'Ошибка: ' + e.message; }
}
</script>
</body>
</html>`,
}}
/>