将布尔搜索查询解析回数组



有没有简单的方法可以将以下字符串解析为数组。我可以将数组转换为字符串,但不知道如何转换回数组。

// Input
"Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
}
]

// Input
"(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
},
{
all: ["Keyword7", "Keyword8"],
any: ["Keyword9", "Keyword10"],
not: ["Keyword11", "Keyword12"]
}
]

首先要做的是:

  1. 我不验证输入。这个答案给了你一种方法。您应该验证输入,特别是因为您说它来自用户:)
  2. 我们将使用此博客中的matchRecursive功能。

此函数将帮助我们对正确的括号进行分组。

var matchRecursive = function () {
var formatParts = /^([Ss]+?)...([Ss]+)/,
metaChar = /[-[]{}()*+?.\^$|,]/g,
escape = function (str) {
return str.replace(metaChar, "\$&");
};
return function (str, format) {
var p = formatParts.exec(format);
if (!p) throw new Error("format must include start and end tokens separated by '...'");
if (p[1] == p[2]) throw new Error("start and end format tokens cannot be identical");
var opener = p[1],
closer = p[2],
/* Use an optimized regex when opener and closer are one character each */
iterator = new RegExp(format.length == 5 ? "["+escape(opener+closer)+"]" : escape(opener)+"|"+escape(closer), "g"),
results = [],
openTokens, matchStartIndex, match;
do {
openTokens = 0;
while (match = iterator.exec(str)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(str.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
};
}();

接下来,这是我根据您提供的数据使用的算法:

  1. 我们通过简单地检查是否有第 1 种输入或第 2 种类型来确定我们是否有str.startsWith("(");
  2. 我们初始化以下内容:

    • groupedItems数组,它将第二种类型的输入转换为第一种类型的输入,以便我们之后对两者使用相同的代码
    • 返回数据的returnArr
  3. 我们在groupedItems上循环并准备一个空keywordObj

  4. 在此循环中,我们通过使用matchRecursive函数并在' OR '后拆分结果来确定哪些是any关键字 - 结果项目将是any项目
  5. 对于其余的关键字(allnot),我们需要得到一个单词 - 所以我们再次拆分,这次是在" "之后,拆分的结果是一组关键字
  6. 我们遍历关键字并通过检查它们是否以-开头来确定它们是否not关键字,否则我们将它们视为all关键字。

这是它的代码:

function output(str){
var groupedItems = [];
if(str.startsWith("(")){
groupedItems = matchRecursive(str,"(...)");
} else {
groupedItems.push(str);
}
var returnArr = [];
for (var i = 0; i<groupedItems.length;i++){
var keywordObj = {all:[], any:[], not: []};
var thisGroup = groupedItems[i];
var arr = matchRecursive(thisGroup, "(...)");
if (arr.length != 1) throw new Error("unexpected input");
keywordObj.any = arr[0].split(" OR ");
var restOfKeywords = thisGroup.split(" (" + arr[0] + ") ");
for (var j = 0; j<restOfKeywords.length; j++){ 
var keyWords = restOfKeywords[j].split(" ");
for (var k = 0; k<keyWords.length;k++){
if (keyWords[k].startsWith("-"))
keywordObj.not.push(keyWords[k])
else 
keywordObj.all.push(keyWords[k])
}
}
returnArr.push(keywordObj);
}
return returnArr;
}
// input "(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// output [{"all":["Keyword1","Keyword2"],"any":["Keyword3","Keyword4"],"not":["-Keyword5","-Keyword6"]},{"all":["Keyword7","Keyword8"],"any":["Keyword9","Keyword10"],"not":["-Keyword11","-Keyword12"]}]

这是一个解决方案 https://codepen.io/anon/pen/NXMoqo?editors=0012

{
// test cases
// const input = 'Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6';
const input = '(Keyword1 Keyword2 (Keyword3 OR  Keyword4) -Keyword5 -Keyword6) OR (Keyword7   Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)';
// const input = '((Keyword1 OR Keyword2 OR Keyword3) Keyword4 Keyword6 -Keyword5 -Keyword7) OR (Keyword8 Keyword9 (Keyword10 OR Keyword11) -Keyword12 Keyword13 -Keyword14 -Keyword15)';
const output = [];
input.split(') OR (').forEach(group => {
let trimmedGroup = group.replace(/^(/, '').replace(/)$/, '');
let anyGroup = trimmedGroup.match(/(.+)/).join('').replace(/[OR)(]/g, '').match(/w+/g);
let notGroup = trimmedGroup.match(/-w+/g).map(element => element.replace('-', ''));
let allGroup = trimmedGroup.replace(/(.+)/g, '').replace(/-w+/g, '').match(/w+/g);
output.push({
all: allGroup,
any: anyGroup,
not: notGroup
});
});
console.log(output);
}

你能检查一下吗

var arr = [], obj = {any:[], not:[], all: []};
function splitString(str) {
	var object = JSON.parse(JSON.stringify(obj));
var strArr = str.split(" ");
var i=0;
while(strArr.length !== 0 && i<10) {
	newStr = strArr.splice(0, 1)[0];
if(newStr.indexOf("(") != -1) {
	while(newStr.indexOf(")") == -1) {
	object.any.push(newStr.replace(")", "").replace("(", ""))
strArr.splice(0, 1);
newStr = strArr.splice(0, 1)[0];
}
object.any.push(newStr.replace(")", ""))
} else if(newStr.indexOf("-") != -1) {
	object.not.push(newStr.substring(1).replace(")", ""))
} else {
	object.all.push(newStr.replace(")", ""))
}
i++;
}
arr.push(object)
}
function convertToObj(string){
	if(string.indexOf(") OR ") !== -1){
		string.split(") OR ").forEach(function(str){
splitString(str.substring(1));
});  
} else {
	splitString(string);
}
}
convertToObj("Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6")
convertToObj("(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)")
console.log(arr)

最新更新