Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Iterate all repeated patterns
  • Loading branch information
wimpyprogrammer committed Apr 18, 2019
1 parent b26b476 commit 3ad7477
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 12 deletions.
43 changes: 35 additions & 8 deletions src/helpers/repetition-pattern.ts
@@ -1,4 +1,4 @@
import { Quantifier, Repetition } from 'regexp-tree/ast';
import { Expression, Quantifier, Repetition } from 'regexp-tree/ast';
import Expander from '../Expander';
import * as Guards from '../types/regexp-tree-guards';

Expand Down Expand Up @@ -28,6 +28,37 @@ function getNumOccurrences(quantifier: Quantifier): [number, number] {
return [from, to !== undefined ? to : 100];
}

function* repeatExpression(
this: Expander,
expression: Expression,
currentDepth: number
): IterableIterator<string> {
if (currentDepth <= 0) {
return yield '';
}

const thisLevel = this.expandExpression(expression);

for (const thisLevelPermutation of thisLevel) {
let isLevelComplete = true;

const remainingLevels = repeatExpression.call(
this,
expression,
currentDepth - 1
);

for (const remainingLevelPermutation of remainingLevels) {
isLevelComplete = false;
yield `${thisLevelPermutation}${remainingLevelPermutation}`;
}

if (isLevelComplete) {
yield thisLevelPermutation;
}
}
}

/**
* Expand an expression that repeats another expression, like "a{1,5}"
* and "(\d|[a-m]){3,}".
Expand All @@ -38,13 +69,9 @@ export function* expandRepetition(this: Expander, node: Repetition) {
const [minOccurrences, maxOccurrences] = getNumOccurrences(node.quantifier);
const numOccurrenceOptions = [...fill(minOccurrences, maxOccurrences)];

const generator = this.expandExpression(node.expression);

for (const expansion of generator) {
const numOccurrenceOptionsSorted = this.sort(numOccurrenceOptions);
const numOccurrenceOptionsSorted = this.sort(numOccurrenceOptions);

for (const numOccurrences of numOccurrenceOptionsSorted) {
yield expansion.repeat(numOccurrences);
}
for (const numOccurrences of numOccurrenceOptionsSorted) {
yield* repeatExpression.call(this, node.expression, numOccurrences);
}
}
83 changes: 79 additions & 4 deletions src/pattern.spec.ts
Expand Up @@ -4,6 +4,12 @@ import {
expandN as expandNWithSort,
} from './pattern';

function* fill(start: number, end: number): IterableIterator<number> {
for (let i = start; i <= end; i++) {
yield i;
}
}

// Keep a stable order for consistent tests.
function sortPreserveOrder<T>(items: T[]) {
return [...items];
Expand Down Expand Up @@ -159,14 +165,74 @@ describe('expand', () => {
'bfg',
'ccf',
'ccfg',
'cccf',
'cccfg',
'cdf',
'cdfg',
'cef',
'cefg',
'dcf',
'dcfg',
'ddf',
'ddfg',
'dddf',
'dddfg',
'def',
'defg',
'ecf',
'ecfg',
'edf',
'edfg',
'eef',
'eefg',
'cccf',
'cccfg',
'ccdf',
'ccdfg',
'ccef',
'ccefg',
'cdcf',
'cdcfg',
'cddf',
'cddfg',
'cdef',
'cdefg',
'cecf',
'cecfg',
'cedf',
'cedfg',
'ceef',
'ceefg',
'dccf',
'dccfg',
'dcdf',
'dcdfg',
'dcef',
'dcefg',
'ddcf',
'ddcfg',
'dddf',
'dddfg',
'ddef',
'ddefg',
'decf',
'decfg',
'dedf',
'dedfg',
'deef',
'deefg',
'eccf',
'eccfg',
'ecdf',
'ecdfg',
'ecef',
'ecefg',
'edcf',
'edcfg',
'eddf',
'eddfg',
'edef',
'edefg',
'eecf',
'eecfg',
'eedf',
'eedfg',
'eeef',
'eeefg',
]);
Expand Down Expand Up @@ -364,6 +430,15 @@ describe('expand', () => {
}
);

it('expands repeated character class', () => {
const allTwoDigitNumbers = [...fill(0, 99)].map(num =>
num.toString().padStart(2, '0')
);

const result = expandAll(/\d{2}/);
expect(result).toEqual(allTwoDigitNumbers);
});

it('ignores boundary anchors', () => {
const result = expandAll('\\bzz\\b \\Bzzz\\B \\bzzzz\\B');
expect(result).toEqual(['zz zzz zzzz']);
Expand Down
9 changes: 9 additions & 0 deletions tsconfig.test.json
@@ -1,4 +1,13 @@
{
"compilerOptions": {
"lib": [
"es5",
"es2015.core",
"es2015.iterable",
"es2016.array.include",
"es2017.string"
]
},
"exclude": [""],
"extends": "./tsconfig.release.json"
}

0 comments on commit 3ad7477

Please sign in to comment.