Regex to match @filter(...)

I am working through the process of building a regex to match all valid @filter(... )

Has anyone done this already to save some time?

Well, my language of choice at the moment (Javascript) does not support recursive regex matching very well. So, I will probably just cheat my code for now and match anything in the @filter string as hopefully being valid. I will have to catch errors later on in the process.

(\s@filter\(.+\))?$
1 Like

Well, if you do it, Do post it here.
would help people like me save some time :smile:

1 Like

Here is where I ended up at if anyone want to pick it up from here…

https://www.regexpal.com/?fam=118254

^\s*@filter\((?:(?:eq|ge|gt|le|lt)\((?:(?:[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?|val\([a-zA-Z0-9_]+\)|count\([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?\)),\s*(?:"[^"]*"|true|false|[0-9]+|val\([a-zA-Z0-9_]+\)|\[(?:"[^"]*"|[0-9]+|val\([a-zA-Z0-9_]+\))(?:,\s*(?:"[^"]*"|[0-9]+|val\([a-zA-Z0-9_]+\)))?\]))\)|(?:allofterms|anyofterms|alloftext|anyoftext)\([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?,\s*"[^"]*"\)|regexp\([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?,\s*\/[^\/]+\/i?\)|has\([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?\)|uid\((?:0x[0-9a-f]+(?:,\s*0x[0-9a-f]+)*|[a-zA-Z0-9]+(?:,\s*[a-zA-Z0-9]+)*)\)|uid_in\([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?,\s*0x[0-9a-f]+\)|match\([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)?,\s*"[^"]*",\s*[1-9][0-9]*\))\)$

Which will successfully match the following:

@filter(has(foo))
@filter(uid(0x1))
@filter(uid(0x2a,0x4f))
@filter(uid(foo))
@filter(uid(foo,bar))
@filter(uid_in(foo,0x3af))
@filter(match(foo,"bar",3))
@filter(match(foo, "baz", 8))
@filter(regexp(foo,/bar/))
@filter(regexp(foo,/bar/i))
@filter(allofterms(foo,"bar"))
@filter(anyofterms(foo,"bar"))
@filter(alloftext(foo,"bar"))
@filter(alloftext(foo,"bar"))
@filter(eq(foo,"bar"))
@filter(gt(foo.bar, true))
@filter(ge(foo, 1))
@filter(lt(foo, val(bar)))
@filter(le(val(foo), "bar"))
@filter(ge(count(foo), 1))
@filter(eq(foo.bar, ["baz"]))
@filter(eq(foo.bar, [1]))
@filter(eq(foo.bar, [val(baz)]))
@filter(eq(foo.bar, ["baz", "quz"]))

And will not match these because they are invalid:

@filter(has(foo.bar.baz))
@filter(uid(val(foo)))
@filter(uid_in(foo,0xz))
@filter(match(foo,"bar",0))
@filter(match(foo, baz, 8))
@filter(regexp(foo,/bar))
@filter(regexp(foo,/bar/g))
@filter(allofterms(foo,bar"))
@filter(anyofterms(foo,"bar))
@filter(alloftext(foo,bar))
@filter(someoftext(foo,"bar"))
@filter(eq(foo,bar))
@filter(gt(foo.bar, null))
@filter(gte(foo, 1))
@filter(lt(foo, val(bar.baz)))
@filter(eq(foo.bar, [true]))

But it should match these combined filters but doesn’t:

@filter(NOT has(foo))
@filter(has(foo) AND has(bar))
@filter(has(foo) OR has(bar))
@filter((has(foo) OR has(bar)))
@filter(NOT (has(foo) OR has(bar)))
@filter(has(foo) OR NOT has(bar))
@filter(NOT has(foo) OR NOT has(bar))
@filter(has(foo) OR (has(bar) AND has(baz)))
@filter(has(foo) OR (has(bar) AND NOT has(baz)))
@filter(has(foo) OR (has(bar) AND (has(baz) OR has(quz))))
1 Like

I would have given up, midway. :sweat_smile:


Attempt 1: Failed

Excerpt from Coding Horror:

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.
– Jamie Zawinski

So I embarked on a quest to find a Machine Learning / Genetic Algorithm based website which would do the job for me.
I found one: Regex Generator & it’s online demo: Regex Golf

I used @amaster507’s sample data to train the model.

Alas, after 1 hour 32 minutes, it failed miserably!


Attempt 2: Promising but Incomplete!

How about using eval to evaluate the filters?!?

Advantages:

  1. Each functions inside the filter will be called individually, so parameters can be contextually checked.
  2. Syntactic errors can be caught with ease.
  3. Easy to understand, and human readable.
  4. Scalable, as adding a new function can be done by adding a new file.
  5. Non existent variables & functions will fail gracefully.
  6. Can be split into multiple files.
const foo = true;
const bar = true;
const baz = true;

function validate(f) {
	f = f.replace(/@/, '').replace(/OR/ig, '||').replace(/AND/ig, '&&').replace(/NOT/ig, '!');

	try {
		console.log(`${eval(f) ? 'Valid' : 'Invalid'}: ${f}`);
	} catch (e) {
		console.log(`Invalid: ${f}`);
	}
}

function filter(x) {
	return x != null;
}

function has(v) {
	return v;
}

function val(x) {
	return x;
}

function count(x) {
	return x;
}

function uid(x, y) {
	return x;
}

function uid_in(x, y) {
	return x;
}

function match(x, y, z) {
	return x;
}

function regexp(x, y) {
	return x;
}

function allofterms(x, y) {
	return (x && typeof y === "string");
}

function anyofterms(x, y) {
	return (x && typeof y === "string");
}

function alloftext(x, y) {
	return (x && typeof y === "string");
}

function eq(x, y) {
	return y;
}

function gt(x, y) {
	return y;
}

function ge(x, y) {
	return y;
}

function lt(x, y) {
	return y;
}

function le(x, y) {
	return y;
}

P.S. Not finishing the above approach, in case the solution is not optimal.