Skip to content

Commit

Permalink
support lookbehind
Browse files Browse the repository at this point in the history
  • Loading branch information
liudongmiao committed Jun 28, 2022
1 parent a5fa510 commit 790dabe
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 8 deletions.
10 changes: 5 additions & 5 deletions dist/regulex.js

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions src/RegExp.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ var NFABuilders=(function _() {
case AssertNegativeLookahead:
f=_negativeLookahead(node);
break;
case AssertLookbehind:
f=_lookbehind(node);
break;
case AssertNegativeLookbehind:
f=_negativeLookbehind(node);
break;
}
return _newAssert(node,from,f);

Expand All @@ -304,10 +310,21 @@ var NFABuilders=(function _() {
return ret.acceptable;
};
}
function _lookbehind(node) {
var m=NFA(tree2NFA(node.sub,['start']));
return function _Lookbehind(stack,c,i,state,s) {
var ret=m.input(s,i,null,stack);
return ret.acceptable;
};
}
function _negativeLookahead(node) {
var f=_lookahead(node);
return function _NLookahead() {return !f.apply(this,arguments)};
}
function _negativeLookbehind(node) {
var f=_lookbehind(node);
return function _NLookbehind() {return !f.apply(this,arguments)};
}

function _isBoundary(i,s) {return !!(_isWordChar(i-1,s) ^ _isWordChar(i,s))}
function _isWordChar(i,s) {return i!==-1 && i!==s.length && /\w/.test(s[i])}
Expand Down
19 changes: 16 additions & 3 deletions src/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ var Constants={
//Assertion Type Constants
AssertLookahead:"AssertLookahead",
AssertNegativeLookahead:"AssertNegativeLookahead",
AssertLookbehind:"AssertLookbehind",
AssertNegativeLookbehind:"AssertNegativeLookbehind",
AssertNonWordBoundary:"AssertNonWordBoundary",
AssertWordBoundary:"AssertWordBoundary",
AssertEnd:"AssertEnd",
Expand Down Expand Up @@ -350,8 +352,14 @@ function _checkRepeat(node) {
if (node.repeat) {
var astype = node.assertionType;
var msg = 'Nothing to repeat! Repeat after assertion doesn\'t make sense!';
if (astype === 'AssertLookahead' || astype === 'AssertNegativeLookahead' ) {
var assertifier = astype === 'AssertLookahead' ? '?=' : '?!';
var assertifiers = {
'AssertLookahead': '?=',
'AssertNegativeLookahead': '?!',
'AssertLookbehind': '?<=',
'AssertNegativeLookbehind': '?<!',
}
var assertifier = assertifiers[astype];
if (assertifier !== undefined) {
var pattern = '('+assertifier+'b)';
msg += '\n/a'+pattern+'+/、/a'+pattern+'{1,n}/ are the same as /a'+pattern+'/。\n' +
'/a'+pattern+'*/、/a'+pattern+'{0,n}/、/a'+pattern+'?/ are the same as /a/。';
Expand Down Expand Up @@ -567,10 +575,13 @@ var actions=(function _() {
group.num=undefined;
stack.groupCounter.i--;
}
function groupToAssertion(stack,c,i) { // Convert /(?!)/,/(?=)/ to AssertNode
function groupToAssertion(stack,c,i,state) { // Convert /(?!)/,/(?=)/ to AssertNode
var group=stack._parentGroup;
group.type=ASSERT_NODE;
group.assertionType= c=='=' ? AssertLookahead : AssertNegativeLookahead ;
if (state === 'groupNameStart') {
group.assertionType= c==='=' ? AssertLookbehind : AssertNegativeLookbehind ;
}
// Caveat!!! Assertion group no need to capture
group.num=undefined;
stack.groupCounter.i--;
Expand Down Expand Up @@ -957,6 +968,8 @@ var config={
['groupQualify>groupQualifiedStart',':',actions.groupNonCapture],//group non-capturing
['groupQualify>groupQualifiedStart','=',actions.groupToAssertion],//group positive lookahead
['groupQualify>groupQualifiedStart','!',actions.groupToAssertion],//group negative lookahead
['groupNameStart>groupQualifiedStart','=',actions.groupToAssertion],//group positive lookbehind
['groupNameStart>groupQualifiedStart','!',actions.groupToAssertion],//group negative lookbehind
['groupQualify>groupQualifiedStart','>',actions.groupAtomicGroup],//group atomic-group
['groupQualify>groupNameStart','<'],
['groupNameStart>groupName','a-zA-Z', actions.groupName],//group name
Expand Down
14 changes: 14 additions & 0 deletions src/visualize.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,14 @@ var plotNode={
fg="Purple";
//txt="Negative\nLookahead!"; // break line
txt="Not followed by:";
} else if (nat === AssertLookbehind) {
lineColor="LightSeaGreen";
fg="Brown";
txt="Preceded by:";
} else if (nat === AssertNegativeLookbehind) {
lineColor="#F69";
fg="MediumVioletRed";
txt="Not preceded by:";
}

var sub=plotNode.group(node,x,y);
Expand Down Expand Up @@ -709,6 +717,8 @@ var hlColorMap={
')':'blue',
'?=':'darkgreen',
'?!':'red',
'?<!':'brown',
'?<=':'darkcyan',
'?:':'grey',
'[':'navy',
']':'navy',
Expand Down Expand Up @@ -740,6 +750,10 @@ function highlight(tree) {
if (node.type===ASSERT_NODE) {
if (node.assertionType===AssertLookahead) {
texts.push(text('?='));
} else if (node.assertionType === AssertLookbehind) {
texts.push(text('?<='));
} else if (node.assertionType === AssertNegativeLookbehind) {
texts.push(text('?<!'));
} else {
texts.push(text('?!'));
}
Expand Down
50 changes: 50 additions & 0 deletions tests/testData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,56 @@ var re2ast =[{ raw: '\\\\{3}',
chars: 'b',
raw: 'b'
}],
}, {
raw: '(?<!foo)bar.*(?<=foo)bar',
groupCount: 0,
tree: [{
type: 'assert',
num: undefined,
sub: [{
type: 'exact',
indices: [4, 7],
chars: 'foo',
raw: 'foo'
}],
indices: [0, 8],
assertionType: 'AssertNegativeLookbehind',
endParenIndex: 7,
raw: '(?<!foo)'
}, {
type: 'exact',
indices: [8, 11],
chars: 'bar',
raw: 'bar',
}, {
type: 'dot',
indices: [11, 13],
repeat: {
min: 0,
max: Infinity,
nonGreedy: false,
possessive: false
},
raw: '.*'
}, {
type: 'assert',
num: undefined,
sub: [{
type: 'exact',
indices: [17, 20],
chars: 'foo',
raw: 'foo'
}],
indices: [13, 21],
assertionType: 'AssertLookbehind',
endParenIndex: 20,
raw: '(?<=foo)'
}, {
type: 'exact',
indices: [21, 24],
chars: 'bar',
raw: 'bar'
}]
}];


Expand Down

0 comments on commit 790dabe

Please sign in to comment.