我试图找到一个字符串在另一个字符串中所有出现的位置,不区分大小写。
例如,给定字符串:
我在黎巴嫩学会了弹尤克里里。
和搜索字符串le
,我想获得数组:
[2, 25, 27, 33]
两个字符串都是变量——也就是说,我不能硬编码它们的值。
我认为这对于正则表达式来说是一件容易的事,但是在努力寻找一个可行的方法之后,我没有运气。
我找到了如何使用 来完成此操作的示例.indexOf()
,但肯定必须有一种更简洁的方法来做到这一点?
我试图找到一个字符串在另一个字符串中所有出现的位置,不区分大小写。
例如,给定字符串:
我在黎巴嫩学会了弹尤克里里。
和搜索字符串le
,我想获得数组:
[2, 25, 27, 33]
两个字符串都是变量——也就是说,我不能硬编码它们的值。
我认为这对于正则表达式来说是一件容易的事,但是在努力寻找一个可行的方法之后,我没有运气。
我找到了如何使用 来完成此操作的示例.indexOf()
,但肯定必须有一种更简洁的方法来做到这一点?
var str = "I learned to play the Ukulele in Lebanon."
var regex = /le/gi, result, indices = [];
while ( (result = regex.exec(str)) ) {
indices.push(result.index);
}
更新
我未能在原始问题中发现搜索字符串必须是一个变量。我已经编写了另一个版本来处理这种使用 的情况indexOf
,所以你回到了你开始的地方。正如 Wrikken 在评论中所指出的那样,要对正则表达式的一般情况执行此操作,您需要转义特殊的正则表达式字符,此时我认为正则表达式解决方案变得比它的价值更令人头疼。
function getIndicesOf(searchStr, str, caseSensitive) {
var searchStrLen = searchStr.length;
if (searchStrLen == 0) {
return [];
}
var startIndex = 0, index, indices = [];
if (!caseSensitive) {
str = str.toLowerCase();
searchStr = searchStr.toLowerCase();
}
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + searchStrLen;
}
return indices;
}
var indices = getIndicesOf("le", "I learned to play the Ukulele in Lebanon.");
document.getElementById("output").innerHTML = indices + "";
<div id="output"></div>
使用String.protype.matchAll
(ES2020)的一个班轮:
[...sourceStr.matchAll(new RegExp(searchStr, 'gi'))].map(a => a.index)
使用您的价值观:
const sourceStr = 'I learned to play the Ukulele in Lebanon.';
const searchStr = 'le';
const indexes = [...sourceStr.matchAll(new RegExp(searchStr, 'gi'))].map(a => a.index);
console.log(indexes); // [2, 25, 27, 33]
如果你担心map()
在一行中做一个传播和一个,我用一个for...of
循环运行它一百万次迭代(使用你的字符串)。一个班轮平均为 1420 毫秒,而for...of
在我的机器上平均为 1150 毫秒。这不是一个微不足道的差异,但是如果您只进行少数比赛,那么一个班轮就可以正常工作。
这是正则表达式免费版本:
function indexes(source, find) {
if (!source) {
return [];
}
// if find is empty string return all indexes.
if (!find) {
// or shorter arrow function:
// return source.split('').map((_,i) => i);
return source.split('').map(function(_, i) { return i; });
}
var result = [];
for (i = 0; i < source.length; ++i) {
// If you want to search case insensitive use
// if (source.substring(i, i + find.length).toLowerCase() == find) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
}
}
return result;
}
indexes("I learned to play the Ukulele in Lebanon.", "le")
编辑:如果你想匹配像 'aaaa' 和 'aa' 这样的字符串来查找 [0, 2] 使用这个版本:
function indexes(source, find) {
if (!source) {
return [];
}
if (!find) {
return source.split('').map(function(_, i) { return i; });
}
var result = [];
var i = 0;
while(i < source.length) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
i += find.length;
} else {
i++;
}
}
return result;
}
你肯定能做到这一点!
//make a regular expression out of your needle
var needle = 'le'
var re = new RegExp(needle,'gi');
var haystack = 'I learned to play the Ukulele';
var results = new Array();//this is the results you want
while (re.exec(haystack)){
results.push(re.lastIndex);
}
编辑:学习拼写 RegExp
另外,我意识到这并不是你想要的,因为它告诉lastIndex
我们针的末端不是开始,但它很接近 - 你可以推re.lastIndex-needle.length
入结果数组......
编辑:添加链接
@Tim Down 的答案使用来自 RegExp.exec() 的结果对象,我所有的 Javascript 资源都掩盖了它的使用(除了给你匹配的字符串)。所以当他使用 时result.index
,那是某种未命名的匹配对象。在exec 的 MDC 描述中,他们实际上非常详细地描述了这个对象。
如果您只想找到所有匹配项的位置,我想向您指出一个小技巧:
var haystack = 'I learned to play the Ukulele in Lebanon.',
needle = 'le',
splitOnFound = haystack.split(needle).map(function (culm)
{
return this.pos += culm.length + needle.length
}, {pos: -needle.length}).slice(0, -1); // {pos: ...} – Object wich is used as this
console.log(splitOnFound);
如果你有一个可变长度的 RegExp,它可能不适用,但对某些人来说它可能会有所帮助。
这是区分大小写的。对于不区分大小写的使用String.toLowerCase
函数之前。
我参加聚会有点晚了(将近 10 年零 2 个月),但未来编码人员的一种方法是使用 while 循环和indexOf()
let haystack = "I learned to play the Ukulele in Lebanon.";
let needle = "le";
let pos = 0; // Position Ref
let result = []; // Final output of all index's.
let hayStackLower = haystack.toLowerCase();
// Loop to check all occurrences
while (hayStackLower.indexOf(needle, pos) != -1) {
result.push(hayStackLower.indexOf(needle , pos));
pos = hayStackLower.indexOf(needle , pos) + 1;
}
console.log("Final ", result); // Returns all indexes or empty array if not found
const findAllOccurrences = (str, substr) => {
str = str.toLowerCase();
let result = [];
let idx = str.indexOf(substr)
while (idx !== -1) {
result.push(idx);
idx = str.indexOf(substr, idx+1);
}
return result;
}
console.log(findAllOccurrences('I learned to play the Ukulele in Lebanon', 'le'));
这是一个简单的代码片段:
function getIndexOfSubStr(str, searchToken, preIndex, output) {
var result = str.match(searchToken);
if (result) {
output.push(result.index +preIndex);
str=str.substring(result.index+searchToken.length);
getIndexOfSubStr(str, searchToken, preIndex, output)
}
return output;
}
var str = "my name is 'xyz' and my school name is 'xyz' and my area name is 'xyz' ";
var searchToken ="my";
var preIndex = 0;
console.log(getIndexOfSubStr(str, searchToken, preIndex, []));
我会推荐蒂姆的答案。然而,@blazs 的这条评论searchStr=aaa
指出“假设和那个str=aaaaaa
。然后你的代码不会找到 4 次出现,因为你在循环中通过 searchStr.length 进行了跳过,而不是找到 2 次。”,通过查看 Tim 的代码,这是正确的,特别是这里的这一行:startIndex = index + searchStrLen;
蒂姆的代码将无法找到正在搜索的字符串的实例,该实例在其自身长度内。所以,我修改了蒂姆的回答:
function getIndicesOf(searchStr, str, caseSensitive) {
var startIndex = 0, index, indices = [];
if (!caseSensitive) {
str = str.toLowerCase();
searchStr = searchStr.toLowerCase();
}
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + 1;
}
return indices;
}
var searchStr = prompt("Enter a string.");
var str = prompt("What do you want to search for in the string?");
var indices = getIndicesOf(str, searchStr);
document.getElementById("output").innerHTML = indices + "";
<div id="output"></div>
如果我有一个 str和一个 searchStr ,将其更改为+ 1
而不是+ searchStrLen
将允许索引 1 位于索引数组中。aaaaaa
aaa
PS如果有人想在代码中添加注释来解释代码是如何工作的,请说出来,我很乐意回复请求。
按照@jcubic 的回答,他的解决方案对我的情况造成了一点混乱
例如var result = indexes('aaaa', 'aa')
将返回[0, 1, 2]
而不是[0, 2]
所以我更新了一些他的解决方案,如下所示以匹配我的情况
function indexes(text, subText, caseSensitive) {
var _source = text;
var _find = subText;
if (caseSensitive != true) {
_source = _source.toLowerCase();
_find = _find.toLowerCase();
}
var result = [];
for (var i = 0; i < _source.length;) {
if (_source.substring(i, i + _find.length) == _find) {
result.push(i);
i += _find.length; // found a subText, skip to next position
} else {
i += 1;
}
}
return result;
}
感谢所有的答复。我浏览了所有这些并想出了一个函数,它为第一个给出每次出现的 'needle' substring 的最后一个索引。我在这里发布它以防它对某人有所帮助。
请注意,它与仅在每次出现的开头的原始请求不同。它更适合我的用例,因为您不需要保持针的长度。
function findRegexIndices(text, needle, caseSensitive){
var needleLen = needle.length,
reg = new RegExp(needle, caseSensitive ? 'gi' : 'g'),
indices = [],
result;
while ( (result = reg.exec(text)) ) {
indices.push([result.index, result.index + needleLen]);
}
return indices
}
检查这个解决方案,它也能找到相同的字符串,让我知道是否有遗漏或不正确。
function indexes(source, find) {
if (!source) {
return [];
}
if (!find) {
return source.split('').map(function(_, i) { return i; });
}
source = source.toLowerCase();
find = find.toLowerCase();
var result = [];
var i = 0;
while(i < source.length) {
if (source.substring(i, i + find.length) == find)
result.push(i++);
else
i++
}
return result;
}
console.log(indexes('aaaaaaaa', 'aaaaaa'))
console.log(indexes('aeeaaaaadjfhfnaaaaadjddjaa', 'aaaa'))
console.log(indexes('wordgoodwordgoodgoodbestword', 'wordgood'))
console.log(indexes('I learned to play the Ukulele in Lebanon.', 'le'))
这是我的代码(使用搜索和切片方法)
let s = "I learned to play the Ukulele in Lebanon"
let sub = 0
let matchingIndex = []
let index = s.search(/le/i)
while( index >= 0 ){
matchingIndex.push(index+sub);
sub = sub + ( s.length - s.slice( index+1 ).length )
s = s.slice( index+1 )
index = s.search(/le/i)
}
console.log(matchingIndex)
这也是我通常用来根据其位置获取字符串索引的方法。
我传递以下参数:
search:要搜索的字符串
find:要查找的字符串
position(默认为'all'):查找字符串在搜索字符串中出现的位置
(如果“全部”返回完整的索引数组)
(如果'last'返回最后一个位置)
function stringIndex (search, find, position = "all") {
var currIndex = 0, indexes = [], found = true;
while (found) {
var searchIndex = search.indexOf(find);
if (searchIndex > -1) {
currIndex += searchIndex + find.length;
search = search.substr (searchIndex + find.length);
indexes.push (currIndex - find.length);
} else found = false; //no other string to search for - exit from while loop
}
if (position == 'all') return indexes;
if (position > indexes.length -1) return [];
position = (position == "last") ? indexes.length -1 : position;
return indexes[position];
}
//Example:
var myString = "Joe meets Joe and together they go to Joe's house";
console.log ( stringIndex(myString, "Joe") ); //0, 10, 38
console.log ( stringIndex(myString, "Joe", 1) ); //10
console.log ( stringIndex(myString, "Joe", "last") ); //38
console.log ( stringIndex(myString, "Joe", 5) ); //[]
嗨朋友们,这只是另一种使用 reduce 和辅助方法查找匹配短语索引的方法。当然 RegExp 更方便,并且可能在内部以某种方式实现。希望对你有帮助。
function findIndexesOfPhraseWithReduce(text, phrase) { //convert text to array so that be able to manipulate. const arrayOfText = [...text]; /* this function takes the array of characters and the search phrase and start index which comes from reduce method and calculates the end with length of the given phrase then slices and joins characters and compare it whith phrase. and returns True Or False */ function isMatch(array, phrase, start) { const end = start + phrase.length; return (array.slice(start, end).join('')).toLowerCase() === phrase.toLowerCase(); } /* here we reduce the array of characters and test each character with isMach function which takes "current index" and matches the phrase with the subsequent character which starts from current index and ends at the last character of phrase(the length of phrase). */ return arrayOfText.reduce((acc, item, index) => isMatch(arrayOfText, phrase, index) ? [...acc, index] : acc, []); } findIndexesOfPhraseWithReduce("I learned to play the Ukulele in Lebanon.", "le");
function findIndexesOfPhraseWithReduce(text, phrase) {
const arrayOfText = [...text];
function isMatch(array, phrase, start) {
const end = start + phrase.length;
return (array.slice(start, end).join('')).toLowerCase() ===
phrase.toLowerCase();
}
return arrayOfText.reduce((acc, item, index) => isMatch(arrayOfText, phrase,
index) ? [...acc, index] : acc, []);
}
console.log(findIndexesOfPhraseWithReduce("I learned to play the Ukulele in Lebanon.", "le"));
function countInString(searchFor,searchIn){
var results=0;
var a=searchIn.indexOf(searchFor)
while(a!=-1){
searchIn=searchIn.slice(a*1+searchFor.length);
results++;
a=searchIn.indexOf(searchFor);
}
return results;
}
下面的代码将为您完成这项工作:
function indexes(source, find) {
var result = [];
for(i=0;i<str.length; ++i) {
// If you want to search case insensitive use
// if (source.substring(i, i + find.length).toLowerCase() == find) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
}
}
return result;
}
indexes("hello, how are you", "ar")
这是 MDN 文档本身的示例:
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);
console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']