UNPKG

locutus

Version:

Locutus other languages' standard libraries to JavaScript for fun and educational purposes

76 lines (75 loc) 2.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.finditer = finditer; const PY_RE_IGNORECASE = 2; const PY_RE_MULTILINE = 8; const PY_RE_DOTALL = 16; function finditer(pattern, source, flags = 0) { // discuss at: https://locutus.io/python/re/finditer/ // parity verified: Python 3.12 // original by: Kevin van Zonneveld (https://kvz.io) // note 1: Returns match records with match text, 0-based index, and capture groups. // note 2: Mirrors Python re.finditer iteration shape with a Locutus-friendly JSONable structure. // example 1: finditer('\\d+', 'a1b22c333') // returns 1: [{match: '1', index: 1, groups: []}, {match: '22', index: 3, groups: []}, {match: '333', index: 6, groups: []}] // example 2: finditer('(\\w+)-(\\d+)', 'x-1 y-20') // returns 2: [{match: 'x-1', index: 0, groups: ['x', '1']}, {match: 'y-20', index: 4, groups: ['y', '20']}] // example 3: finditer('abc', 'ABC abc', 2) // returns 3: [{match: 'ABC', index: 0, groups: []}, {match: 'abc', index: 4, groups: []}] const input = String(source); const regex = createGlobalRegex(pattern, flags); const out = []; regex.lastIndex = 0; while (true) { const match = regex.exec(input); if (!match) { break; } out.push({ match: match[0] ?? '', index: match.index, groups: match.slice(1).map((value) => value ?? ''), }); if ((match[0] ?? '') === '') { if (regex.lastIndex >= input.length) { break; } regex.lastIndex += 1; } } return out; } function createGlobalRegex(pattern, flags) { const source = pattern instanceof RegExp ? pattern.source : String(pattern); const base = pattern instanceof RegExp ? pattern.flags : ''; const extra = normalizeRegexFlags(flags); const combined = dedupeFlags((base + extra).replace(/g/g, '').replace(/y/g, '')); return new RegExp(source, `${combined}g`); } function normalizeRegexFlags(flags) { if (typeof flags === 'string') { return dedupeFlags(flags.replace(/[^dgimsuvy]/g, '')); } let out = ''; if (flags & PY_RE_IGNORECASE) { out += 'i'; } if (flags & PY_RE_MULTILINE) { out += 'm'; } if (flags & PY_RE_DOTALL) { out += 's'; } return out; } function dedupeFlags(flags) { const seen = new Set(); let out = ''; for (const flag of flags) { if (!seen.has(flag)) { seen.add(flag); out += flag; } } return out; }