Skip to content

Commit d3b1e93

Browse files
authored
[patch] simplify pseudo greps before converting to regular expression (#31)
1 parent d90c085 commit d3b1e93

File tree

3 files changed

+129
-6
lines changed

3 files changed

+129
-6
lines changed

.github/workflows/build.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
run: npm run cov:show
6464

6565
- name: Archive code coverage results
66-
uses: actions/upload-artifact@v3
66+
uses: actions/upload-artifact@v4
6767
with:
6868
name: code-coverage-report
6969
path: ./reports/coverage-full-total/

src/utils/regexp.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
type Replacement = { order: number; mapName: string; exp: string; inverse: boolean };
22

3+
export const simplifyParentheses = (input: string): string => {
4+
// Replace deeply nested parentheses with a single group
5+
let simplified = input;
6+
7+
while (/\(\(([^()]+)\)\)/.test(simplified)) {
8+
simplified = simplified.replace(/\(\(([^()]+)\)\)/, '($1)');
9+
}
10+
11+
return simplified.replace(/&\(\.\*\)/g, '');
12+
};
13+
314
/**
415
* replace all parenthesis groups with placeholder
516
* @param input
617
* @param replacements
718
* @param num
819
*/
9-
const replaceParenthesisGroups = (input: string, replacements: Replacement[], num = 1): string => {
10-
let replaced = input;
20+
export const replaceParenthesisGroups = (input: string, replacements: Replacement[], num = 1): string => {
21+
let replaced = simplifyParentheses(input);
1122
const groupsNeg = input.match(/!\(([^()]*)\)/);
1223
const groups = input.match(/\(([^()]*)\)/);
1324

@@ -26,6 +37,10 @@ const replaceParenthesisGroups = (input: string, replacements: Replacement[], nu
2637
if (groupsNeg) {
2738
return replaceExpression(groupsNeg[0], groupsNeg[1], true);
2839
} else if (groups) {
40+
if (replaced === '(.*)') {
41+
return '';
42+
}
43+
2944
return replaceExpression(groups[0], groups[1], false);
3045
}
3146

@@ -37,7 +52,7 @@ const replaceParenthesisGroups = (input: string, replacements: Replacement[], nu
3752
* @param exp
3853
* @param inverse
3954
*/
40-
const convertOneGroup = (exp: string, inverse: boolean): string => {
55+
export const convertOneGroup = (exp: string, inverse: boolean): string => {
4156
const reg = exp
4257
.split('/')
4358
.map(t => (t.startsWith('!') ? t.replace(/^!(.*)/, '^(?!.*$1.*)') : t))
@@ -83,6 +98,7 @@ export const selectionTestGrep = (str: string): RegExp => {
8398
});
8499

85100
convertedString = convertedString
101+
.replace(/\.\*\.\*/g, '.*')
86102
.replace(new RegExp(leftParenth, 'g'), '\\(')
87103
.replace(new RegExp(rightParenth, 'g'), '\\)');
88104

tests/test-folder/regexp.test.ts

+109-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { selectionTestGrep } from '../../src/utils/regexp';
1+
import { convertOneGroup, selectionTestGrep, simplifyParentheses } from '../../src/utils/regexp';
22
import expect from 'expect';
33

44
describe('suite', () => {
@@ -68,7 +68,7 @@ describe('suite', () => {
6868
{
6969
desc: 'parenthesis several more complex - many parent parenthesis',
7070
GREP: '((((((.*)&!((my test)|(his test))&(.*))))))',
71-
regExpected: /(?=.*.*)+(?=.*^(?!.*(my test|his test).*))+(?=.*.*)+.*/i,
71+
regExpected: /(?=.*)+(?=.*^(?!.*(my test|his test).*))+.*/i,
7272
cases: [
7373
{ expectMatch: true, testLine: 'test her' },
7474
{ expectMatch: true, testLine: 'her test' },
@@ -376,6 +376,23 @@ describe('suite', () => {
376376
{ expectMatch: false, testLine: '@otherTest' },
377377
],
378378
},
379+
{
380+
desc: 'simplify regexp',
381+
GREP: '(.*)&((((.*))))',
382+
regExpected: /.*/i,
383+
cases: [{ expectMatch: true, testLine: '@test sdd @test2 dsd' }],
384+
},
385+
{
386+
desc: 'simplify regexp',
387+
GREP: '((((((((((((((@V1&!@V2)&(.*)))&(.*)))&(.*)))&(@V1&!@V2)))&(.*)))&(.*))))', // '(@V1&!@V2)&(@V1&!@V2)',
388+
regExpected: /(?=.*(?=.*@V1)+^(?!.*@V2.*)+)+(?=.*(?=.*@V1)+^(?!.*@V2.*)+)+.*/i,
389+
cases: [
390+
{ expectMatch: false, testLine: '@V1 sdd @V2 dsd' },
391+
{ expectMatch: false, testLine: '@V2 sdd @V1 dsd' },
392+
{ expectMatch: true, testLine: '@V1 sdd dsd' },
393+
{ expectMatch: false, testLine: '@V3 sdd dsd' },
394+
],
395+
},
379396
])
380397
.each(t => t.cases)
381398
// .only(t => t.id === '1')
@@ -395,4 +412,94 @@ describe('suite', () => {
395412
}
396413
});
397414
});
415+
416+
it('should simplify expression', () => {
417+
const grep = '(.*)&((((.*))))';
418+
const regActual = selectionTestGrep(grep);
419+
420+
expect(regActual).toEqual(/.*/i);
421+
});
422+
423+
describe('simplifyParentheses', () => {
424+
it('simplifyParentheses 1', () => {
425+
const grep = '(.*)&((((.*))))';
426+
expect(simplifyParentheses(grep)).toEqual('(.*)');
427+
});
428+
429+
it('simplifyParentheses 2', () => {
430+
const grep = '(.*)&((((.*))))&((((something))))';
431+
expect(simplifyParentheses(grep)).toEqual('(.*)&(something)');
432+
});
433+
434+
it('simplifyParentheses 3', () => {
435+
const grep = '(.*)&((((.*))))&((((something))))';
436+
expect(simplifyParentheses(grep)).toEqual('(.*)&(something)');
437+
});
438+
439+
it('simplifyParentheses 4', () => {
440+
const grep = '(.*)&((((.*))))&(((((A)&(B|(V&D))))))&((((something))))';
441+
expect(simplifyParentheses(grep)).toEqual('(.*)&(((((A)&(B|(V&D))))))&(something)');
442+
});
443+
444+
it('simplifyParentheses incorrect', () => {
445+
const grep = '(.*)&((((.*))))&((((something)))))';
446+
expect(simplifyParentheses(grep)).toEqual('(.*)&(something))');
447+
});
448+
});
449+
450+
describe('simplify expression', () => {
451+
it('should simplify expression 1', () => {
452+
const grep = '(.*)&((((.*))))';
453+
const regActual = selectionTestGrep(grep);
454+
455+
expect(regActual).toEqual(/.*/i);
456+
});
457+
458+
it('should simplify expression 2', () => {
459+
const grep = '(A)&((((C))))';
460+
const regActual = selectionTestGrep(grep);
461+
462+
expect(regActual).toEqual(/(?=.*A)+(?=.*C)+.*/i);
463+
});
464+
465+
it('should simplify expression - groups inside parenthesis', () => {
466+
const grep = '(.*)&((((.*))))&(((((A)&(B|(V&D))))))&((((something))))';
467+
const regActual = selectionTestGrep(grep);
468+
469+
expect(regActual).toEqual(/(?=.*)+(?=.*(?=.*A)+(?=.*(B|(?=.*V)+(?=.*D)+))+)+(?=.*something)+.*/i);
470+
expect(regActual.test('A')).toEqual(false);
471+
expect(regActual.test('A gogo B else something')).toEqual(true);
472+
expect(regActual.test('B gogo A else something')).toEqual(true);
473+
expect(regActual.test('V gogo A else something D')).toEqual(true);
474+
expect(regActual.test('V gogo A else something')).toEqual(false);
475+
expect(regActual.test('X')).toEqual(false);
476+
});
477+
478+
it('should simplify expression 4', () => {
479+
const grep = '(.*)&((((.*))))&((((something))))';
480+
const regActual = selectionTestGrep(grep);
481+
482+
expect(regActual).toEqual(/(?=.*)+(?=.*something)+.*/i);
483+
});
484+
});
485+
486+
describe('convertOneGroup', () => {
487+
it('convertOneGroup 1', () => {
488+
const grep = '.*';
489+
const regActual = convertOneGroup(grep, false);
490+
expect(regActual).toEqual('.*');
491+
});
492+
493+
it('convertOneGroup 2 - or', () => {
494+
const grep = 'A|C';
495+
const regActual = convertOneGroup(grep, false);
496+
expect(regActual).toEqual('(A|C)');
497+
});
498+
499+
it('convertOneGroup 3 - and', () => {
500+
const grep = 'A&C';
501+
const regActual = convertOneGroup(grep, false);
502+
expect(regActual).toEqual('(?=.*A)+(?=.*C)+');
503+
});
504+
});
398505
});

0 commit comments

Comments
 (0)