【问题标题】:Parse boolean search query back to array将布尔搜索查询解析回数组
【发布时间】:2018-01-12 06:48:02
【问题描述】:

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

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

【问题讨论】:

  • 你认为重新提问会让你的问题变得更好吗?你试过什么?
  • 我认为这个问题有很多反对意见,最好重写我的问题。我仍在努力寻找解决方案。
  • 很多人反对...?投票计数器是正面的(当前)
  • 不是为了这个问题,我以不同的方式问了同样的问题......我想用更好的方式重写我的问题@snap

标签: javascript parsing


【解决方案1】:

第一件事:

  1. 我不验证输入。这个答案为您提供了一种方法。您应该验证输入,特别是因为您说它来自用户:)
  2. 我们将使用来自this blogmatchRecursive 函数。

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

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. 在这个循环中,我们通过使用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"]}]

【讨论】:

  • 感谢您的回答。你真棒。让我检查一下。
【解决方案2】:

这是一个解决方案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
【解决方案3】:

你能检查一下吗

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)

【讨论】:

  • 无法说出用户可能输入的内容,因此无法假设任何内容。该代码可能适用于指定的输入,但并不总是有效,因为例如,如果用户在两者之间放置两个空格,或者您的代码将中断。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-30
  • 2018-10-10
相关资源
最近更新 更多