如何在JavaScript中查找一个字符串中所有出现的索引?

Bun*_*gle 83 javascript regex string indexof

我试图在另一个字符串中找到所有出现的字符串的位置,不区分大小写.

例如,给定字符串:

I learned to play the Ukulele in Lebanon.

和搜索字符串le,我想获取数组:

[2, 25, 27, 33]
Run Code Online (Sandbox Code Playgroud)

两个字符串都是变量 - 也就是说,我不能对它们的值进行硬编码.

我认为对于正则表达式来说这是一个简单的任务,但经过一段时间的努力找到一个可行的表达式之后,我没有运气.

我找到了如何使用这个实例的例子.indexOf(),但肯定有一个更简洁的方法来做到这一点?

Tim*_*own 141

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);
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

我没有在原始问题中发现搜索字符串需要是一个变量.我已经写了另一个版本来处理这个使用的案例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 + "";
Run Code Online (Sandbox Code Playgroud)
<div id="output"></div>
Run Code Online (Sandbox Code Playgroud)

  • 假设`searchStr=aaa`和`str=aaaaaa`。然后,您的代码不会找到 4 次出现,而只会找到 2 次,因为您正在循环中通过 `searchStr.length` 进行跳过。 (4认同)
  • `le` 在这里如何成为可变字符串?即使在使用 `new Regexp(str);` 时,特殊字符的危险也潜伏着,例如搜索 `$2.50`。类似`regex = new Regexp(dynamicstring.replace(/([\\.+*?\\[^\\]$(){}=!&lt;&gt;|:])/g, '\\$1') );` 会更接近恕我直言。我不确定 js 是否有内置的正则表达式转义机制。 (2认同)

Ben*_*chs 17

一个衬垫使用String.protype.matchAll(ES2020):

[...sourceStr.matchAll(new RegExp(searchStr, 'gi'))].map(a => a.index)
Run Code Online (Sandbox Code Playgroud)

使用你的价值观:

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]
Run Code Online (Sandbox Code Playgroud)

如果您担心map()在一行中进行传播和 a ,我会用for...of循环运行它进行一百万次迭代(使用您的字符串)。一个班轮平均为 1420 毫秒,而for...of在我的机器上平均为 1150 毫秒。这不是一个微不足道的区别,但是如果您只进行少量比赛,则一个衬垫可以正常工作。

请参见matchAll上caniuse


jcu*_*bic 15

这是正则表达式免费版:

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")
Run Code Online (Sandbox Code Playgroud)

编辑:如果你想匹配像'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;
}
Run Code Online (Sandbox Code Playgroud)

  • +1.我运行了一些测试,以便与使用Regex的解决方案进行比较.最快的方法是使用Regex的方法:http://jsperf.com/javascript-find-all (5认同)

Ryl*_*ley 12

你确定可以做到这一点!

//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);
}
Run Code Online (Sandbox Code Playgroud)

编辑:学习拼写RegExp

此外,我意识到这不是正是你想要什么,lastIndex告诉我们针不是开始的结束,但它很接近-你可以推re.lastIndex-needle.length到结果数组...

编辑:添加链接

@Tim Down的答案使用了RegExp.exec()中的结果对象,我的所有Javascript资源都掩盖了它的使用(除了给你匹配的字符串).因此,当他使用时result.index,这是某种未命名的匹配对象.在execMDC描述中,他们实际上以相当详细的方式描述了这个对象.


小智 8

我参加聚会有点晚了(差不多 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
Run Code Online (Sandbox Code Playgroud)


Vic*_*tor 6

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'));
Run Code Online (Sandbox Code Playgroud)