forked from siegebell/vsc-prettify-symbols-mode
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathregexp-iteration.ts
72 lines (64 loc) · 2.74 KB
/
regexp-iteration.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
export interface MatchResult {
start: number,
end: number,
matchStart: number,
matchEnd: number,
id: number,
}
/**
* Iterates through each match-group that occurs in the `str`; note that the offset within the given string increments according with the length of the matched group, effectively treating any other portion of the matched expression as a "pre" or "post" match that do not contribute toward advancing through the string.
* The iterator's `next' method accepts a new offset to jump to within the string.
*/
export function *iterateMatches(str: string, re: RegExp, start?: number) : IterableIterator<MatchResult> {
re.lastIndex = start===undefined ? 0 : start;
let match : RegExpExecArray;
while((match = re.exec(str))) {
if(match.length <= 1)
return;
const validMatches = match
.map((value,idx) => ({index:idx,match:value}))
.filter((value) => value.match !== undefined);
if(validMatches.length > 1) {
const matchIdx = validMatches[validMatches.length-1].index;
const matchStr = match[matchIdx];
const matchStart = match.index;
const matchEnd = matchStart + match[0].length;
const start = matchStart + match[0].indexOf(matchStr);
const end = start + matchStr.length;
const newOffset = yield {start: start, end: end, matchStart: matchStart, matchEnd: matchEnd, id: matchIdx-1};
if(typeof newOffset === 'number')
re.lastIndex = Math.max(0,Math.min(str.length,newOffset));
else
re.lastIndex = end;
}
}
}
export function *iterateMatchArray(str: string, res: RegExp[], start?: number) : IterableIterator<MatchResult> {
start = start===undefined ? 0 : start;
res.forEach(re => re.lastIndex = start);
let matches = res.map(re => re.exec(str));
let matchIdx = matches.findIndex(m => m && m.length > 1);
while(matchIdx >= 0) {
const match = matches[matchIdx];
const matchStr = match[1];
const matchStart = match.index;
const matchEnd = matchStart + match[0].length;
const start = matchStart + match[0].indexOf(matchStr);
const end = start + matchStr.length;
const newOffset = yield {start: start, end: end, matchStart: matchStart, matchEnd: matchEnd, id: matchIdx};
if(typeof newOffset === 'number') {
const next = Math.max(0,Math.min(str.length,newOffset));
res.forEach(re => re.lastIndex = next)
} else
res.forEach(re => re.lastIndex = end)
matches = res.map(re => re.exec(str));
matchIdx = matches.findIndex(m => m && m.length > 1);
}
}
export function *mapIterator<T1,T2>(iter: IterableIterator<T1>, f: (x:T1)=>T2, current?: IteratorResult<T1>) : IterableIterator<T2> {
if(!current)
current = iter.next();
while(!current.done) {
current = iter.next(yield f(current.value));
}
}