Коротка відповідь
middleФункція використовує RegExp `/<a\s+(?:[^>]*?\s+)?href=("[^"]*"|'[^']*'|[^\s>]+)[^>]*>/gi` і `matchAll`, щоб повернути масив URL‑ів. Приклад: `const links = [...str.matchAll(regex)].map(m=>m[1]);`
Повне пояснення
Що це і навіщо
Функція шукає всі атрибути href у тегах <a> в HTML‑рядку, що корисно для парсингу посилань без DOM.
Принцип роботи / алгоритм
RegExp розпізнає тег <a>, пропускає будь‑які атрибути, потім ловить значення href, яке може бути в лапках або без них. matchAll повертає ітератор всіх збігів, а група 1 містить саме URL.
Реалізація (JS / TS)
function extractLinks(html){
const regex = /<a\s+(?:[^>]*?\s+)?href=("[^"]*"|'[^']*'|[^\s>]+)[^>]*>/gi;
return [...html.matchAll(regex)].map(m=>m[1]);
}
Тестування
test('extracts multiple links', ()=>{
const html = '<a href="/home">Home</a> <a href=/about>About</a>';
expect(extractLinks(html)).toEqual(['/home', '/about']);
});
Проблеми та edge cases
- Вкладені теги – RegExp не розбирає вкладення, але це не критично для простого парсингу.
- Крапка з комою у URL – регулярка дозволяє, бо ловить до пробілу або
>. - Скрипти/стилі – якщо
<a>вбудований у скрипт, RegExp все одно його знайде; треба фільтрувати контекст. - Мульти‑рядкові атрибути – RegExp працює, бо
.не включає новий рядок; можна додати флагs. - Кодовані посилання – RegExp не декодує, тому треба обробляти після.
Оптимізація та продуктивність
Для великих документів використовуйте String.prototype.search з флагом g, а не matchAll, якщо потрібен лише перший URL. Якщо потрібно обробляти багато рядків, кешуйте RegExp.
Без JS / архітектурні альтернативи
У браузері можна отримати посилання через document.querySelectorAll('a[href]') і пройтись по .href. У Node.js без DOM можна використати cheerio.
Cheatsheet + follow-up
- Cheatsheet:
/<a\s+(?:[^>]*?\s+)?href=("[^"]*"|'[^']*'|[^\s>]+)[^>]*>/gi - Interview question: Як змінити RegExp, щоб ігнорувати атрибути
target? - Follow‑up: Як обробити посилання, що містять
javascript:?