【问题标题】:Match part of string against array of string in javascript将字符串的一部分与javascript中的字符串数组匹配
【发布时间】:2017-11-13 02:13:30
【问题描述】:

我有一个包含 1500 个 varint 字符串的数组,如下所示:

 var base = ["129;176;2","131;173;2","242;1","221;188;2","138;7","201;20","251;12","32"]

数组的字符串可以由单个数字(“32”)、两个数字(“242;1”)或三个数字(“131;173;2”)组成,不超过3个数字。

还有一个变量,其中包含从数组中包含的字符串的串联获得的字符串(该变量由用户创建,并且只能从可以在基本数组中找到的值列表中创建)。

 var userCreated = "129;176;2;32;131;173;2;184;3;201;20;251;12"

问题是在数组中找到完美匹配,但我不知道要检查的正确部分。

例如: 我不知道我是否必须匹配“129”或“129;176”或“129;176;2”,所以我需要一个可以匹配第一个数字,第一个和第二个数字,以及第一个的函数,第二个和第三个数字。当找到完美匹配时,必须将字符串的一部分存储在新变量中并从原始变量(userCreated)中删除。

一个数字我就可以做到:

 var divide = userCreated.split(";");
 for (var i = 0;i<divide.length; i++){
         if(base.indexOf(divide[i]) >= 0){
            var found + i = divide[i];
         }
 }

是否可以按顺序检查 var 中的字符串与数组以找到完美匹配,然后检查字符串的其余部分?重要的是要注意:匹配可以在“完美匹配”之前找到(检查“129”可以找到匹配,但在基本数组中可以有一个“129;176”(完美匹配)所以其他值可能不匹配...

编辑: 为了澄清这个问题: userCreated 字符串不能包含两次要在数组中匹配的值。例如:它可以包含 126;15 和 126;15;2 但不能包含 126;15 或 126;15;2 两次。 预期的结果可以是一系列变量,里面每个“完美匹配”,例如:

 var found0 = "129;176;2";
 var found1 = "242;1";
 var found2 = "32";

或者像原始数组这样的数组:

 var found = ["129;176;2", "242;1", "32"] // Maybe a better solution

总匹配数在 1 到 30 匹配范围内。

编辑(解决方案): 在接受(和好的)答案之后,我尝试遵循类似的方式: 我已将原始数组拆分为 3 个数组,如下所示:

 base1 = ["28", "34", "16"];
 base2 = ["125;16", "200;45", "167;2"];
 base3 = ["209;145;2", "143;154;2", "211;170;2", "246;170;2", "247;170;2"];

然后:

 var divide = userCreated.split(";"),
     resultArray3 = [], resultArray2 = [], resultArray1 = [], final = [];
 function tri(divide){
 for (var i = 0, j = 1, k = 2; k<divide.length; i++, j++, k++){
    var tre = base3.indexOf(divide[i]+';'+divide[j]+';'divide[k]);
    if (tre !== -1){
        resultArray3.push(base3[tre]);
        divide.splice(i, 1, "none");
        divide.splice(j, 1, "none");
        divide.splice(k, 1, "none");
    }
 }
 }
 function two(divide){
     for (var i = 0, k = 1; k<divide.length; i++, k++){
            var due = base2.indexOf(divide[i]+';'+divide[k]);
        if (due !== -1){
            resultArray2.push(base2[due]);
            divide.splice(i, 1, "none");
            divide.splice(k, 1, "none");
        }
 }
 }
 function ones(divide){
 for (var k = 0; k<divide.length; k++){
    var uno = base1.indexOf(divide[k]);
        if (uno !== -1){
            resultArray1.push(base1[uno]);
            divide.splice(k, 1, "none");
        }
}
 }

最后:

final.push.apply(final, resultArray1);
final.push.apply(final, resultArray2);
final.push.apply(final, resultArray3);

【问题讨论】:

  • 129;176;2;,你怎么可能知道它是否等同于129;176; 2;129; 176;2;?您的分隔符与应合并的数字指示符相同。
  • 那么,var found = base.filter(item =&gt; ~`;${userCreated};`.indexOf(`;${item};`)) 有用吗?
  • 您能否从您的示例值中指定所需的结果
  • @ObsidianAge 两个变量中的分隔符都可以更改,挑战是在这种情况下找到完全匹配,知道吗?
  • 这不适用于输入 "1;2;3;4"base=["1", "2", "3;4"; "1;2;3"]。正确的解决方案是 ["1", "2", "3;4"],但是如果您从处理三元组开始,您会找到 "1;2;3" 并以 "4" 结尾,它没有匹配项。

标签: javascript arrays match


【解决方案1】:

正如@ObsidianAge 所说,可能有多种方法可以将输入字符串拆分为匹配的部分。如果可能的话,我会检查输入是否必须是这种方式。

我不确定是什么阻止了您追求您描述的解决方案...最简单的实现涉及递归:

let base = ["129", "129;176", "129;176;2","131;173;2","242;1","221;188;2","138;7","201;20","251;12","32", "184;3", "176"]
let userCreated = '129;176;2;32;131;173;2;184;3;201;20;251;12';

let appendSemicolon = (str) => str + ";";
let removeSemicolon = (str) => str.substr(0, str.length-1);

base = base.map(appendSemicolon); // so that '1' is not matched as a prefix of '12;34'

function findMatch(input, depth=0) {
  // returns an array of arrays where:
  //    solutions[i].join("") == input
  //    solutions[i][j] is a string from `base`
  // (empty array if no such solutions exist)
  let solutions = [];
  base.forEach((prefix) => {
    if (!input.startsWith(prefix)) return;
    let rest = input.substr(prefix.length);
    
    if (rest.length === 0) {
      // easy case: the input has a 'perfect match' in `base`
      console.log(" ".repeat(depth) + `checking '${prefix}' - matching complete!`)
      solutions.push([prefix]);
    } else {
      // we found a matching prefix. It will be a valid solution iff
      // the rest of input can be constructed from the strings in `base`
      console.log(" ".repeat(depth) + `checking '${prefix}' (rest='${rest}')`)
      let subSolutions = findMatch(rest, depth+1);
      solutions = solutions.concat(subSolutions.map((sol) => [prefix].concat(sol)));
    }
  });
  return solutions;
}

findMatch(userCreated + ";").map((parts) => parts.map(removeSemicolon));

请注意,您没有指定输入字符串中是否允许重复条目,我没有尝试对此进行优化,并且我使用的是 JS 较新版本中的一些语法,这可能不被普遍支持所有浏览器。

【讨论】:

  • 在 userCreated 中不能包含重复项,至少“完美”匹配不能是重复项。例如:它可以包含 126;15 和 126;15;2 但不能包含 126;15 或 126;15;2 两次。我不熟悉 JS 的最新版本,所以你的代码对我来说有点“晦涩”!午饭后我会检查你的解决方案,谢谢! P.S.:我已将我的问题编辑得更具体。
  • 我的示例没有过滤掉包含重复匹配项的解决方案;您可以通过传递尚未匹配的条目数组以及 input 来添加它。
  • 如果您需要有关新语法的文档的指针,请随时询问 - 我没有使用太多 - (x)=&gt;f(x) 语法是 function (x) { return f(x) }mapforEach 不是很新,其余的应该是不言自明的。
  • 我没有得到以下部分:深度、concat(sol)(什么是 SOL?)、前缀是关键字?它没有在任何地方声明......无论如何,我按照你的建议在问题中寻求我的第一个解决方案,我会接受你的回答,因为它给我带来了正确的方式!我的版本在更新的问题中;)
  • base.forEach((prefix) =&gt; { 表示“循环遍历base 数组的所有元素,在每次迭代中让prefix 成为数组的当前元素并执行括号内的代码”。因此,我们尝试base 中的每个组合,以查看输入字符串是否以它开头。如果是,我们将其切掉,看看是否可以解析输入字符串的其余部分 (rest)。我无法在此处的评论中解释递归,您应该查一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-20
  • 1970-01-01
  • 2021-04-28
相关资源
最近更新 更多