Skip to content

Commit

Permalink
Extract matches by group name
Browse files Browse the repository at this point in the history
  • Loading branch information
ljdavies committed Apr 27, 2020
1 parent 3ea3144 commit bb8fade
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 2 deletions.
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,85 @@ builder.matchesString('helloearth'); // false
```
## Examples
The exceptional expressions builder class exposes many methods for chaining expressions in various combinations. These methods, combined with the various utility functions provide extensive functionality such as named grouping, or and optional chaining, exclusions and many more.
```javascript
// Optional chaining
import { ExpBuilder, or, Constants, Sequences } from 'exceptional-expressions;

const builder = new ExpBuilder('g');

builder
.beginsWith('(a)')
.orBeginsWith('(b)')
.followedBy(Constants.whitespace)
.followedBy(or([Constants.word, Sequences.numbers(3)]));

builder.matchesString('(a) Test'); // true
builder.matchesString('(b) word'); // true
builder.matchesString('(a)string'); // false
builder.matchesString('(a) 123'); // true

builder.getMatches('(a) first extra test string (b) second');
// ['(a) first']

builder.toRegex(); // /^(?:(?:\(a\))|(?:\(b\)))\s(?:(?:[A-Za-z']+\b)|(?:[\d]{3}))/g

```

Named groups allow you to group chunks of your expression and then extract that chunk by the name that you gave it. This functionality seeks to improve on the `regex.exec(string)` method, which requires you to keep careful track on the ordering of your regex capture groups in order to determine which array index your group will be extracted into.

```javascript
// Named groups
import { ExpBuilder, group, Constants } from 'exceptional-expressions;
const builder = new ExpBuilder('g');
builder
.contains(group([Constants.word, '.', Constants.word], 'username'))
.followedBy('@')
.followedBy(
group([
group(Constants.word, 'company'), '.', group(Constants.word, 'tld')
], 'domain')
);
builder.getCaptureGroups();
// ['username', 'domain', 'company', 'tld']
builder.matchesString('[email protected]');
// true
builder.getMatchesWithGroups('[email protected], [email protected]')
/* [{
match: '[email protected]',
groups:
{
username: 'test.person',
domain: 'example.com',
company: 'example',
tld: 'com'
}
},
{
match: '[email protected]',
groups:
{
username: 'another.guy',
domain: 'test.io',
company: 'test',
tld: 'io'
}
}]
*/
builder.getMatchesByGroup('[email protected], [email protected]', 'company')
// ['example', 'test']
```
## License
[MIT](LICENSE)
2 changes: 1 addition & 1 deletion __tests__/builder/beginsWith.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Sequences from '../../src/sequences';
* beginsWith test
*/
describe('beginsWith test', () => {
let builder: ExpressionBuilder = new ExpressionBuilder();
let builder: ExpressionBuilder = new ExpressionBuilder('g');

beforeEach(() => {
builder.reset();
Expand Down
71 changes: 71 additions & 0 deletions __tests__/builder/getMatchesByGroup.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import ExpressionBuilder from '../../src/exceptional-expressions';
import { group } from '../../src/utils';
// import Sequences from '../../src/sequences';
import Constants from '../../src/constants';

describe('getMatches test', () => {
let builder: ExpressionBuilder = new ExpressionBuilder('g');
let match: string | any[];

beforeEach(() => {
builder.reset();
});

it('extracts all groups by name', () => {
builder
.contains(group([Constants.word, '.', Constants.word], 'username'))
.followedBy('@')
.followedBy(
group([group(Constants.word, 'company'), '.', group(Constants.word, 'tld')], 'domain')
);

match = builder.getMatchesByGroup('[email protected], [email protected]', 'username');
expect(match.length).toEqual(2);
expect(match).toEqual(['test.person', 'another.guy']);

match = builder.getMatchesByGroup('[email protected], [email protected]', 'company');
expect(match.length).toEqual(2);
expect(match).toEqual(['example', 'test']);

match = builder.getMatchesByGroup('[email protected], [email protected]', 'domain');
expect(match.length).toEqual(2);
expect(match).toEqual(['example.com', 'test.io']);

match = builder.getMatchesByGroup('[email protected], [email protected]', 'tld');
expect(match.length).toEqual(2);
expect(match).toEqual(['com', 'io']);
});

it('extracts all groups by index', () => {
builder
.contains(group([Constants.word, '.', Constants.word]))
.followedBy('@')
.followedBy(group([group(Constants.word), '.', group(Constants.word)]));

match = builder.getMatchesByGroup('[email protected], [email protected]', 1);
expect(match.length).toEqual(2);
expect(match).toEqual(['test.person', 'another.guy']);

match = builder.getMatchesByGroup('[email protected], [email protected]', 3);
expect(match.length).toEqual(2);
expect(match).toEqual(['example', 'test']);

match = builder.getMatchesByGroup('[email protected], [email protected]', 2);
expect(match.length).toEqual(2);
expect(match).toEqual(['example.com', 'test.io']);

match = builder.getMatchesByGroup('[email protected], [email protected]', 4);
expect(match.length).toEqual(2);
expect(match).toEqual(['com', 'io']);
});

it('extracts exmpty array where invalid group given', () => {
builder
.contains(group([Constants.word, '.', Constants.word]))
.followedBy('@')
.followedBy(group([group(Constants.word), '.', group(Constants.word)]));

match = builder.getMatchesByGroup('[email protected], [email protected]', 'test');
expect(match.length).toEqual(0);
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "exceptional-expressions",
"version": "0.2.2",
"version": "0.2.3",
"description": "An incredible way to build efficient, concise and human readable regular expressions.",
"keywords": [
"typescript",
Expand Down
5 changes: 5 additions & 0 deletions src/exceptional-expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
validateFlags,
extractMatches,
extractMatchesWithGroup,
extractMatchesByGroup,
IGroupings,
} from './helpers';

Expand Down Expand Up @@ -38,6 +39,10 @@ export default class ExpressionBuilder {
return extractMatchesWithGroup(string, this.buildExpression(), this.getCaptureGroups());
}

public getMatchesByGroup(string: string, group: string | number): string[] {
return extractMatchesByGroup(string, group, this.buildExpression(), this.getCaptureGroups());
}

public getCaptureGroups(): Array<string | number> {
return this.groups.map((group, index) => (group.startsWith('__') ? index + 1 : group));
}
Expand Down
14 changes: 14 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,20 @@ export const extractMatchesWithGroup = (
return groupings;
};

export const extractMatchesByGroup = (
string: string,
group: string | number,
regex: RegExp,
groups: Array<string | number>
): Array<string> => {
const extractions: Array<string>[] = extractAllMatches(string, regex);
const groupIndex = groups.indexOf(group);

if (groupIndex === -1) return [];

return extractions[groupIndex + 1];
};

const extractAllMatches = (string: string, regex: RegExp) => {
const matches: Array<string[]> = [];
let match: RegExpExecArray | null;
Expand Down

0 comments on commit bb8fade

Please sign in to comment.