Reputation: 2049
I'm working on a custom search feature for a blog I'm coding from scratch. This blog is geared towards the technically inclined readers, and I wanted to allow readers to search through articles by defining some advanced search criteria in the search field (as opposed to having multiple search inputs, one for title, one for tags, one for category.. etc). Somewhat similar to Jiras advanced search or Googles search operators.
I will be coding this in Javascript, but Ill be using the xRegExp library, which supports all the cool features that the native RegExp doesnt (named group matching, look ahead, look behind, etc)
The "fields" that are searchable would be:
To add a search "field" to the search criteria, you would just type one of the fields names above, then a colon (:
), then the search phrase associated to that field.
In addition to that, I would like to allow the viewer to add some "OR" and "AND" logic to the search criteria, such as searching for articles with the author john.doe OR mike.smith, or articles with the tags bash AND scripting. The OR operator could be ||
, and the AND operator could be &&
.
Some example search strings:
author:linus tag:linux How Linux got started
author:john.doe||jane.smith categories:infosec||linux tags:linux&&security Securing your first Linux server
I was hoping to get as much of the string parsing done via Regex as I could. I got a little something going on regex101, but im having a problem with matching for a pattern multiple times, separated by spaces.. So any help would be appreciated. Thanks!
Upvotes: 0
Views: 434
Reputation: 265
ps. sorry I didn't use your lib. I ussually only fall back to libs if I really need to. Didn't read your message well enough. Other than that I think the code is readable/easy to edit (unlike most regexp's).
I saw the nodejs tag as well, if you are using this to 'send' you can easily translate the pairs to key/values like this:
const pairSeperator = ':';
const valueSeperators = [
{ splitter: '||', replacingValue: 'OR' },
{ splitter: '&&', replacingValue: 'AND' },
];
const validKeyNames = [
'title',
'summary',
'author',
'category',
'tag',
'created',
'updated',
];
function isValidKeyValuePair(input) {
const possiblePair = input.split(pairSeperator);
if (possiblePair.length == 2) {
return validKeyNames.indexOf(possiblePair[0]) > -1;
}
return false;
}
function parseValue(value) {
const valueSeperator = valueSeperators.find((s) => value.indexOf(s.splitter) > -1);
if (valueSeperator) {
return value
.split(valueSeperator.splitter)
.join(` ${valueSeperator.replacingValue} `);
}
return value;
}
function pairReduce(memo, strPair) {
const [key, value] = strPair.split(pairSeperator);
obj[key] = parseValue(value);
return obj;
}
// this is function which handles your searchTerm
function parseSearch(searchTerm) {
const splittedSearchTerm = searchTerm.split(' ');
const filters = splittedSearchTerm
.filter(isValidKeyValuePair)
.reduce(pairReduce, {});
const searchTerm = splittedSearchTerm
.filter(input => !isKeyValuePair(input))
.join(' ');
return Object.assign(filters, { searchTerm });
// input: parseSearch("tag:linux why Linux rocks?");
// output: { "tag": "linux", "searchTerm": "why Linux rocks?" }
}
Upvotes: 1