简体   繁体   中英

Match part of string against array of string in javascript

I have an array with 1500 strings of varint like this:

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

The strings of the array can be formed by a single number ("32"), two numbers ("242;1") or three numbers ("131;173;2"), not more than 3 number.

And a variable that contain a string obtained from the concatenation of the strings contained in the array (that variable is created by the user and only from a list of values that can be found in the base array).

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

The problem is find a perfect match in the array, but I cannot know the right part to check.

For example: I do not know if I've to match "129" or "129;176" or "129;176;2", so I need a function that can match the first number, the first and the second numbers, and the first, the second and the third number. When a perfect match is found that portion of string have to be stored in a new variable and removed from the original variable (userCreated).

With a single number I can do:

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

It's possible check sequentially the string in the var against the array to find a perfect match and then check for the rest of the string? It's important to notice that: a match can be found before the "perfect match" (check for "129" can find a match, but there can be a "129;176" in the base array (the perfect match) so the others values can be mismatched...

EDIT: To clarify the question: The userCreated string can't contain twice a value to be matched in the array. For example: It can contain 126;15 and 126;15;2 but not 126;15 or 126;15;2 twice. The expected result can be a series of variable with inside every "perfect match", such as:

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

or an array like the original array so:

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

The number of total match it's in a range from 1 match to 30 match.

EDIT (solution): After the accepted (and good) answer I've tried to follow a similar way: I've split my original array in 3 arrays like this:

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

then:

 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");
        }
}
 }

and finally:

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

As @ObsidianAge notes, there might be multiple ways to split the input string into matching portions. I would check if the inputs have to be this way, if possible.

I'm not sure what stopped you from pursuing the solution you described... the easiest implementation of this involves recursion:

 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)); 

Note that you didn't specify if duplicate entries are allowed in the input string, I'm not trying to optimize this, and I'm using some syntax from the newer revisions of JS, which may not be universally supported by all browsers yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM