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

时间:2018-01-12 06:48:02

标签: javascript parsing

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

 // 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"]
     }
 ]

3 个答案:

答案 0 :(得分:2)

首先要做的事情:

  1. 我没有验证输入。这个答案给你一个方法。您应该验证输入,特别是因为您说它来自用户:)
  2. 我们将使用this blog中的matchRecursive函数。
  3. 此功能将帮助我们对正确的括号进行分组。

    var matchRecursive = function () {
        var formatParts = /^([\S\s]+?)\.\.\.([\S\s]+)/,
            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. 我们确定是否有第一种输入或第二种类型,只需检查str.startsWith("(");
    2. 我们初始化以下内容:

      • groupedItems表示将第二类输入转换为第一类输入的数组,以便我们之后使用相同的代码
      • returnArr表示返回的数据
    3. 我们遍历groupedItems并准备一个空的keywordObj

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

      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"]}]
      

答案 1 :(得分:1)

以下是解决方案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);
}

答案 2 :(得分:0)

你可以查看这个

吗?

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)