| index.mjs | ||
| package.json | ||
| README.md | ||
regexoid
funny regex thingy
this library exposes a singular function called regexoid:
import { regexoid } from 'regexoid';
// var { regexoid } = require('regexoid');
// create a regex factory-function
let regex = regexoid(({ seq, any }) => (
seq(any('Goodbye','Hello'),' ','world!')
// matches either "Goodbye world!" or "Hello world!"
));
// instantiate a regex
let eater = regex()
// process text
console.log(eater('Hello world!'))
// { done: true, match: {}, count: 12 }
the regexoid() function calls the user-provided function f with an object
full of helper functions r provided as the first argument. f must return
a "regex element", which is one of:
- a string (matches itself)
- the return value of one of the helper functions:
chars(pred): match a single character if the predicate function returns trueseq(...elems): match every passed regex element one after anotherany(...elems): match any of the regex elements (or rather, the longest matching; if multiple are the same length, first in the list wins)rep(lim: [int,int], ...elems): repeat the match at leastlim[0](or 0) times and no more thanlim[1](or Infinity) timescapture(key, ...elems): "capture" the enclosed elements into a named variable in the results. if the value already exists, regex matching abortsmark(key, value): set a named variable to the specified valuecaptureMulti,markMulti: same as previous two, but append to array instead of setting the variablemap(fn): callfnpassing an object with the following helper functions:get(k): get a value from the captures set (nullif missing). note that lists/"multi captures" makegetreturn an iterator from the last capture to the firstset(k,v): set a value to the captures set; if any existed it will be replaced. null deletes the valueadd(k,v): add a value to a list in the captures set; if the key is already taken by a non-list value the operation fails and returns false (otherwise true)fnmay return a value. if the value isfalse, regex matching aborts
abort(): abort regex matching
the regex elements may be mixed and matched to produce a complex regex
regexoid() returns a constructor function that can then be used to instantiate
a regex processing stream. the regex instance is also a function, taking
a chunk of text as argument and returning the result of parsing, i.e an object
with the following fields:
- done:
falseif the regex accepts more data,trueotherwise - match: when the regex is done, this will contain any variables captured by the regex.
- count: sometimes the regex may finish before reading the whole chunk, this allows you to know how many characters of the regex were actually read
regex matching is always anchored to the beginning. captures are only present in the results table
when the path the capture is in is actually taken and matched; that also means you can
re-use the same name for multiple different captures even without captureMulti/markMulti, as long
as only one of them is matched in any given run (e.g. if they're in distinct branches of an any()).
pass no arguments to the regex object will signal EOF to the regex.
More complex example:
import { regexoid } from 'regexoid';
let o = regexoid(({
seq, any, rep, chars,
mark, markMulti,
capture, captureMulti,
map, abort,
}) => (
(({field, spc}) => (
field = (field => () => any(
field(),
captureMulti('unknownFields',
rep([1,], chars(c => c >= 'a' && c <= 'z'
|| c >= 'A' && c <= 'Z')),
any('',seq('(',rep([],chars(c => c != ')')),')'))
),
))(field),
seq(
spc(), rep([], field(), any(',',';'), spc()), field(), spc()
)
))({
field: () => (any(
...['meow', 'meower', 'sigma', 'susser']
.map(k => (
seq(
seq(
...[...k]
.map(e => [e.toLowerCase(),e.toUpperCase()])
.map(([l,h]) => chars(e => e==l || e==h))
),
any(
mark('value', true),
seq('(',
capture('value',
rep([], chars(c => c != ')'))
)
,
')')
),
map(({ get, set, add }) => {
let v = get('value');
if (v == 'BAD')
return false;
set('value');
add(k, v);
}),
)
))
)),
spc: (lim=[]) => rep(
lim,
chars(c => c==' '
|| c == '\t'
|| c == '\n'
|| c == '\r'))
})
))();
[
o(`
meow(sussy);
Meower, meo`),o(`wer(2), meower(3),
Unknownus(hmm?),
meower(BAD),
sigma(meo`),
o(`wer)`),
o('')
]
.map(e=>console.log('result:',e))
/*
result: { done: false, count: 33 }
result: { done: false, count: 70 }
result: { done: false, count: 4 }
result: {
done: true,
match: {
meow: [ 'sussy' ],
meower: [ true, '2', '3' ],
unknownFields: [ 'Unknownus(hmm?)', 'meower(BAD)' ],
sigma: [ 'meower' ]
},
count: 0
}
*/
performance
no
bugs
Yes