# regexoid funny regex thingy this library exposes a singular function called `regexoid`: ```js 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 true - `seq(...elems)`: match every passed regex element one after another - `any(...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 least `lim[0]` (or 0) times and no more than `lim[1]` (or Infinity) times - `capture(key, ...elems)`: "capture" the enclosed elements into a named variable in the results. if the value already exists, regex matching aborts - `mark(key, value)`: set a named variable to the specified value - `captureMulti`, `markMulti`: same as previous two, but append to array instead of setting the variable - `map(fn)`: call `fn` passing an object with the following helper functions: - `get(k)`: get a value from the captures set (`null` if missing). note that lists/"multi captures" make `get` return an iterator from the last capture to the first - `set(k,v)`: set a value to the captures set; if any existed it will be replaced. null deletes the value - `add(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) `fn` may return a value. if the value is `false`, 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: `false` if the regex accepts more data, `true` otherwise - 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: ```js 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