简介
在处理字符串或大量的文本时,你可能会遇到这样的情况:你需要计算一个特定的子串在另一个字符串中出现了多少次。
在这篇文章中,我们将看看如何使用JavaScript来计算一个字符串中出现的子串的数量。我们将研究获得这个数字的各种方法和手段。
但在开始之前,我们首先要定义什么是子串。
什么是子串?
子串是一个字符串中明确定义的连续字符序列。例如,如果我们有一个字符串*"我叫John Doe",那么"name is "是一个子串,但是"is name "不是,因为它不再是一个连续的序列(我们改变了单词的顺序)。像"是 "和"名 "*这样的单个词总是子串。
注意: *"y name is Jo "也是"My name is John Doe "*的一个有效子串。换句话说,子串并不总是完整的词,它们的可读性会差很多。
在JavaScript中,有很多方法可以实现这一点,但有两个主要方法是split() 方法和正则表达式。
用*split()*方法计算字符串中子串的数量
split() 是一种JavaScript方法,用于将字符串分割成一个子字符串数组,同时保留原始字符串。这个方法接受一个分隔符,并根据它来分离字符串。如果没有提供分隔符,split() ,返回一个只有一个元素的数组--原始字符串。
**注意:**最明显的分离器的例子可能是空白。 当你为split() 方法提供它作为分隔符时,只要有空白出现,原始字符串就会被切开。因此,split() 方法将从原始字符串中返回一个单独的单词数组。
在这篇文章中,我们将使用一个方便的技巧来获得一个字符串中子串的出现次数。我们将在split() 方法中设置子串为分隔符。这样,我们就可以从split() 方法返回的数组中提取子串出现的次数。
let myString = "John Doe has 5 oranges while Jane Doe has only 2 oranges, Jane gave Mike 1 of her orange so she is now left with only 1 Orange.";
let mySubString = "orange";
let count = myString.split(mySubString).length - 1;
console.log(count); // 3
上面的代码返回了3 ,但是myString 中只有*"orange "这个字符串的一个实例。 让我们通过检查我们用"orange "*作为分隔符分割原始字符串后创建的数组来检查发生了什么。
console.log(myString.split(mySubString));
这将给我们带来。
['John Doe has 5 ', 's which Jane Doe has only 2 ', 's, Jane gave Mike 1 of her ', ' so she is now left with only 1 Orange.']
从本质上讲,split() 方法从原始字符串中删除了*"orange "*字符串的所有出现,并在删除子串的地方将其切开。
注意**:注意这如何适用于字符串"oranges"--"orange "是它的子串,因此,split() 删除了"orange",只留下*"s"*。
由于我们已经找到了三个 "orange "字符串的出现,原始字符串在三个地方被切开了--因此我们产生了四个子串。这就是为什么我们在计算子串的出现次数时需要从数组的长度中减去1 。
这一切都很好,但是原始字符串中还有一个橙色--最后一个词是*"Orange"。为什么我们在前面的例子中没有计算它呢?那是因为split() 方法是区分大小写的*,因此它认为*"orange "和"Orange "*是不同的元素。
如果你需要使你的代码不区分大小写,一个好的解决方案是首先将整个字符串和子串转换成特定的文本大小写,然后再检查出现的情况。
let myString = "John Doe has 5 oranges while Jane Doe has only 2 oranges, Jane gave Mike 1 of her orange so she is now left with only 1 Orange.";
let mySubString = "ORANGE";
let myStringLC = myString.toLowerCase();
let mySubStringLC = mySubString.toLowerCase();
let count = myStringLC.split(mySubStringLC).length - 1;
console.log(); // 4
此外,我们可以做的最后一件事是用一个函数来包装我们的代码,使其可以重复使用。
const countOccurence = (string, word) => {
let stringLC = string.toLowerCase();
let wordLC = word.toLowerCase();
let count = stringLC.split(wordLC).length - 1;
return count
};
用RegEx计算字符串中子串的数量
另一种计算出现次数的方法是使用正则表达式(RegEx)。它们是用于搜索、匹配和验证字符串的字符模式。正则表达式最常见的用例可能是表单验证--检查字符串是否是一个(有效的)电子邮件、电话号码等。但是在这篇文章中,我们将用它来计算一个字符串中的子串出现的次数。
首先,我们需要定义一个正则表达式来匹配我们要找的子串。假设我们想在一个更大的字符串中找到*"orange "*这个字符串的出现次数,我们的正则表达式将如下所示。
let regex = /orange/gi;
在JavaScript中,我们在两个正斜杠之间写一个正则表达式模式 -/pattern/ 。另外,在第二个正斜杠之后,你可以放一个标志列表--用来交替匹配模式时的默认行为的特殊字符。
例如,默认情况下,正则表达式只匹配搜索字符串中第一次出现的模式。而且,匹配是区分大小写的,这也许不是我们在搜索子串时想要的。正因为如此,我们将介绍两个标志,我们将在本文中使用。
g- 确保我们得到模式的所有出现(不仅仅是第一个)。i- 确保匹配是不区分大小写的。
**注意:**根据你的需要,你可以选择你要使用的标志。这些并不是强制性的。
现在,让我们使用先前创建的正则表达式来计算字符串*"orange "*在myString 中出现的次数。
let myString = "John Doe has 5 oranges while Jane Doe has only 2 oranges, Jane gave Mike 1 of her orange so she is now left with only 1 Orange.";
let regex = /orange/gi;
let count = (myString.match(regex) || []).length;
console.log(count); // 4
**注意:**我们已经添加了 || [] ,如果没有匹配,则返回一个空数组。因此,出现的次数将被设置为0 。
另外,我们可以使用RegExp() 构造函数来创建一个正则表达式。它接受一个搜索模式作为第一个参数,并接受标志作为第二个参数。
let myString = "John Doe has 5 oranges while Jane Doe has only 2 oranges, Jane gave Mike 1 of her orange so she is now left with only 1 Orange.";
let regex = new RegExp("orange", "gi");
let count = (myString.match(regex) || []).length;
console.log(count); // 4
此外,我们还可以通过将其包装在一个单独的函数中,使其可以重复使用。
let countOcurrences = (str, word) => {
var regex = new RegExp(word, "gi");
let count = (str.match(regex) || []).length;
return count;
};
严格匹配精确短语
有时,你想匹配一个严格的短语或单词--所以*"oranges "不包括在你的计数中,或者任何本身包括"orange",但不是严格的"orange "*的单词。这是在字符串中搜索字符串的一个更具体的用例,幸运的是,这很容易!通过将我们的术语包裹在。
let regex = /\Worange\W/gi;
通过将我们的术语包裹在\W \W ,我们严格匹配*"orange"(不区分大小写),这个重构词在我们的句子中只匹配两次(两个"oranges "*都没有被匹配)。
基准测试性能
当我们使用JS基准运行这两种方法时,拆分法总是比重词法快,尽管这一点即使对于相当大的文本语料库来说也不是很明显。你使用这两种方法可能都会很好。
**注意:**不要依赖这些基准作为你的最终决定。相反,你可以自己测试一下,以确定哪一个是最适合你的特定使用情况的。
总结
在这篇文章中,我们了解了两种计算字符串中子串出现次数的标准方法。我们还对结果进行了基准测试,并指出,只要你采取的方法对你有用,其实并不重要。