测试字符串是否包含组成另一个字符串的所有字符

3

我正在尝试使用JavaScript来确定一个字符串是否包含了另一个字符串所包含的所有字符。

例如,单词“hello”包含了构成单词“hell”的所有字符。同样地,“hellowy”也包含了构成单词“yellow”的所有字符。

最重要的是,这种方法需要在两个字符串的字符顺序不同的情况下仍然能够运行。此外,字符数也很重要。“Hel”并不包含构成“hell”所需的所有字符。这严格指的是字符数量:一个“hell”需要两个l,而“hel”只有一个。

更进一步地解释这个问题,如果在将字符串中的字符组合成子字符串后还剩下一些“未使用”的字符,我不会为此担心。也就是说,“helll”仍然应该包含单词“hell”的所有字母。

如何高效地实现这个目标?或许有一个正则表达式的解决方案吗?速度是有点问题,但不是绝对关键。


“Hel” 不包含组成 “hell” 的所有字符吗?"hel" 包含了构成 "hell" 的所有字符。你是指大小写敏感吗? - guest271314
不。只有通过字符的数量来判断。你需要两个“l”才能组成单词“hell”,而“hel”只有一个。 - MadPhysicist
请注意,这是一个重要的要求,似乎在原始问题中没有包含?您应该能够检查输入字符串的长度是否等于匹配字符串的长度。 - guest271314
我现在会加上。 - MadPhysicist
5个回答

5
你可以使用 every 方法:
function test(string, substring) {
    var letters = [...string];
    return [...substring].every(x => {
        var index = letters.indexOf(x);
        if (~index) {
            letters.splice(index, 1);
            return true;
        }
    });
}

每个变量都将在第一个假值处失败,然后它不会搜索每个字母。

1
@MadPhysicist。例如,它可以是:((new Set).add, mySet) - Washington Guedes
我认为这不是必需的,能否给一个例子? - Washington Guedes
@guest271314,我不确定你对什么感到困惑。在你指出关于字符数量和字母大小写的混淆后,我更新了问题。由于字符数量对我的情况很重要,所以我更新了问题。 - MadPhysicist
@MadPhysicist "由于字符数量在我的情况下很重要,我更新了问题。" 是的,接受的答案没有检查输入和匹配字符串的.length是否相同;你试过test("hell", "hel")吗?预期结果应该是false,对吗? - guest271314
1
@guest271314 在这一点上,你我都无能为力。此外,这也是为什么我会给每个试图回答我的问题的人点赞的原因。 - MadPhysicist
显示剩余20条评论

1

我做了一些训练,得到了这个东西:

function test(str, substring) {
  var arr_str = str.toLowerCase().split('');
  var arr_substr = substring.toLowerCase().split('');

  return arr_substr.filter(function(each) {
    return arr_str.indexOf(each) === -1;
  }).length === 0;
}

console.log(test("Alien", "line")); // true
console.log(test("Hello", "hello")); // true
console.log(test("hello", "hey")); // false

1

编辑,已更新

此外,字符数也很重要。 "Hel"并不包含所有构成“hell”的字符。

您可以使用变量来存储布尔值,使用for..of循环,使用String.prototype.indexOf()检查,设置布尔变量,如果falsebreak循环。

您还应该能够在if条件中包括检查输入字符串.length是否等于匹配字符串.length,如果两个字符串的.length属性不相等,则将变量设置为false

var str = "hell";
var match = "hel";
var bool = true; 
for (var prop of str) {
  if (str.length !== match.length || match.indexOf(prop) === -1) {
    bool = false; break;
  }
};
console.log(bool); // false

1
如果字母数量很重要,那么可能会像这样:
function test(string, substring) {
    var regexp = new RegExp(substring.split("").sort().map(function(s) { return s + "+"; }).join(""));
    return regexp.test(string.split("").sort().join(""));
}

这种方法比上面的答案慢,但如果字符串中有一些重复的部分,那么可以进行缓存,以获得比其他答案更好的速度表现。
var cache1 = { };
var cache2 = { };
function test2(string, substring) {
    var regexp = cache1[substring];
    if (!regexp) {
        regexp = new RegExp(substring.split("").sort().map(function(s) { return s + "+"; }).join(""));
        cache1[substring] = regexp;
    }

    var string2 = cache2[string];
    if (!string2) {
        string2 = string.split("").sort().join("");
        cache2[string] = string2;
    }

    return regexp.test(string2);
}

1
我参考了其他人的评论尝试了一些东西,得出了如下结论。它基本上每当子字符串中的一个字母返回正索引值时使用一个 count 变量,然后检查总计数是否等于子字符串的长度(逻辑是返回 -1 的任何字母都不存在且不会被计数)。如果计数相等,则所有字母都通过了测试;如果不相等,则测试失败。

对于反转字母、子字符串中重复的字母(即 'heell' 作为子字符串也会通过 'hello' 进行测试),此方法均有效。

function test(str, substring) {
    let str1 = str.toLowerCase();
    let str2 = substring.toLowerCase();
    let count = 0;
    let answer = false;

    for(let i of str2){
        if(str1.indexOf(i) >= 0) {
            count+=1;
        }
    }
    return str2.length == count ? answer = true : answer;
}

console.log(test("Alien", "line")); // true
console.log(test("Hello", "olleh")); // true
console.log(test("hello", "hey")); // false


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接