Javascript 查找字符串中指定字符的所有索引

Javascript 查找字符串中指定字符的所有索引,javascript,string,indexing,Javascript,String,Indexing,例如,如果我在变量中有“剪刀”,并且想知道字母“s”的所有出现位置,它应该打印出1、4、5、8 如何以最有效的方式在JavaScript中实现这一点?我不认为在整个过程中循环是非常有效的一个简单的循环很有效: var str = "scissors"; var indices = []; for(var i=0; i<str.length;i++) { if (str[i] === "s") indices.push(i); } 现在它将给你你的预期结果 可以看到小提琴 我不认为

例如,如果我在变量中有
“剪刀”
,并且想知道字母
“s”
的所有出现位置,它应该打印出
1、4、5、8


如何以最有效的方式在JavaScript中实现这一点?我不认为在整个过程中循环是非常有效的

一个简单的循环很有效:

var str = "scissors";
var indices = [];
for(var i=0; i<str.length;i++) {
    if (str[i] === "s") indices.push(i);
}
现在它将给你你的预期结果

可以看到小提琴

我不认为在整个过程中循环是非常有效的

就性能而言,我不认为这是你需要严重担心的事情,直到你开始遇到问题

下面是一个比较各种答案的测试。在Safari 5.1中,IndexOf的性能最好。在Chrome19中,for循环最快

使用本机方法最有效地查找每个偏移量

function locations(substring,string){
  var a=[],i=-1;
  while((i=string.indexOf(substring,i+1)) >= 0) a.push(i);
  return a;
}

console.log(locations("s","scissors"));
//-> [0, 3, 4, 7]
然而,这是一个微观优化。对于足够快的简单简洁的循环:

// Produces the indices in reverse order; throw on a .reverse() if you want
for (var a=[],i=str.length;i--;) if (str[i]=="s") a.push(i);    
事实上,chrome上的本机循环比使用
indexOf
更快

请注意,JavaScript从0开始计数。如果必须,请将+1添加到
i

当我对所有的东西进行基准测试时,似乎正则表达式表现得最好,所以我提出了这个

function indexesOf(string, regex) {
    var match,
        indexes = {};

    regex = new RegExp(regex);

    while (match = regex.exec(string)) {
        if (!indexes[match[0]]) indexes[match[0]] = [];
        indexes[match[0]].push(match.index);
    }

    return indexes;
}
你可以这样做

indexesOf('ssssss', /s/g);
哪个会回来

{s: [0,1,2,3,4,5]}
我需要一种非常快速的方法来匹配大量文本中的多个字符,例如,您可以这样做

indexesOf('dddddssssss', /s|d/g);
你会得到这个

{d:[0,1,2,3,4], s:[5,6,7,8,9,10]}

通过这种方式,您可以一次获得所有匹配项的索引,这更有趣,也更一般:它可以查找字符串中任意长度的子字符串的起始索引

const length=(x)=>x.length
常数和=(a,b)=>a+b
const indexesOf=(substr)=>({
在:(str)=>(
str
.split(substr)
.slice(0,-1)
.地图(长度)
.map((u,i,长度)=>(
长度
.slice(0,i+1)
.reduce(总和,i*substr.长度)
))
)  
});
console.log(indexesOf('s')。in('scissors');//[0,3,4,7]

console.log(indexesOf('and')。in('a、b和c');//[2,8]
您也可以使用javascript的match()函数。可以创建正则表达式,然后将其作为参数传递给match()


这将返回一个包含所有字母“s”的数组。

我喜欢这个问题,并想使用数组中定义的
reduce()
方法来编写我的答案

function getIndices(text, delimiter='.') {
    let indices = [];
    let combined;

    text.split(delimiter)
        .slice(0, -1)
        .reduce((a, b) => { 
            if(a == '') {
                combined = a + b;
            } else { 
                combined = a + delimiter + b;
            } 

            indices.push(combined.length);
            return combined; // Uncommenting this will lead to syntactical errors
        }, '');

    return indices;
}


let indices = getIndices(`Ab+Cd+Pk+Djb+Nice+One`, '+');
let indices2 = getIndices(`Program.can.be.done.in.2.ways`); // Here default delimiter will be taken as `.`

console.log(indices);  // [ 2, 5, 8, 12, 17 ]
console.log(indices2); // [ 7, 11, 14, 19, 22, 24 ]

// To get output as expected (comma separated)
console.log(`${indices}`);  // 2,5,8,12,17
console.log(`${indices2}`); // 7,11,14,19,22,24

为了进一步解决问题,以下是我的解决方案: 您可以找到字符串中存在的字符索引:

findIndex(str, char) {
    const strLength = str.length;
    const indexes = [];
    let newStr = str;

    while (newStr && newStr.indexOf(char) > -1) {
      indexes.push(newStr.indexOf(char) + strLength- newStr.length);
      newStr = newStr.substring(newStr.indexOf(char) + 1);
    }

    return indexes;
  }

findIndex('scissors', 's'); // [0, 3, 4, 7]
findIndex('Find "s" in this sentence', 's'); // [6, 15, 17]


下面是一个使用函数表达式(带有ES6箭头函数)的简短解决方案。函数接受字符串和要查找的字符作为参数。它将字符串拆分为一个字符数组,并使用
reduce
函数将匹配索引累加并作为数组返回

const findIndices = (str, char) =>
  str.split('').reduce((indices, letter, index) => {
    letter === char && indices.push(index);
    return indices;
  }, [])
测试:

findIndices("Hello There!", "e");
// → [1, 8, 10]

findIndices("Looking for new letters!", "o");
// → [1, 2, 9]

这是一个紧凑的(单线)版本:


使用while循环

let索引=[];
让数组=“剪刀”。拆分(“”);
让元素='s';
设idx=array.indexOf(element);
而(idx!==-1){
指数推送(idx+1);
idx=array.indexOf(元素,idx+1);
}

控制台日志(索引)另一种选择可能是使用

var getindex=(s,t)=>{
return[…s].flatMap((char,i)=>(char==t?i+1:[]);
};
log(getindex('scissors','s');

log(getindex('kaios','0')
你真的不想要基于1的字符索引,是吗?除非你有一个大字符串,或者有很多字符串,或者这种情况经常发生(比如每秒100次),否则在整个字符串中循环可能就足够了。重要的不是它的效率有多高,而是它是否有效。请注意,字符的位置从
0
(而不是
1
)开始,这一点令人困惑,但您可以通过练习自动完成“我不认为整个循环非常有效”-如何能够在不循环整个字符串的情况下测试字符串中的每个字符?即使有一个内置的
.indexOfAll()
方法,它也必须在后台循环…正如@vcsjones提到的,如果你(疯狂地)想要基于1的值,
.push(i+1)
。+1,但建议在推送内容后使用反向?使用
unshift();我还没有测试过
unshift()
的速度,但是对于大型阵列来说,它可能比
.push()
更慢。reverse()
@p true,push+reverse的性能似乎更好。感谢+1带来的功能性乐趣,即使与OP所要求的相比效率非常低。@jezternz可能不是最快的实际上,它非常慢+1到目前为止,这是最快的解决方案。哈哈,我们三个都做了自己的JSPerf测试;)请注意,Chrome上的循环速度更快,但Firefox和IE上的循环速度较慢(根据我的测试)。@Phrogz啊,对不起。我的意思是“在Safari中,indexOf是最快的。将它添加到indexOf最快的浏览器列表中”@Phrogz和vcsjones:
charAt()
更可靠这就是你应该如何真正测试它,分离出你正在测量的东西:根据我在chrome上运行的基准测试,在一个非常小的字符串上,vcsjones仍然是最快的Yes,但是看看当你增加haystack时会发生什么:。没有竞争,在我的场景中,我需要的是能够匹配大文本集而不是小字符串的东西。啊,好吧,公平点:),也许你应该将该图添加到你的答案中,以明确为什么你的解决方案实际上是最有效率的。这不会给出索引。@vivex它会给出索引。match函数返回附加属性,在这些属性中可以看到匹配结果的索引
function getIndices(text, delimiter='.') {
    let indices = [];
    let combined;

    text.split(delimiter)
        .slice(0, -1)
        .reduce((a, b) => { 
            if(a == '') {
                combined = a + b;
            } else { 
                combined = a + delimiter + b;
            } 

            indices.push(combined.length);
            return combined; // Uncommenting this will lead to syntactical errors
        }, '');

    return indices;
}


let indices = getIndices(`Ab+Cd+Pk+Djb+Nice+One`, '+');
let indices2 = getIndices(`Program.can.be.done.in.2.ways`); // Here default delimiter will be taken as `.`

console.log(indices);  // [ 2, 5, 8, 12, 17 ]
console.log(indices2); // [ 7, 11, 14, 19, 22, 24 ]

// To get output as expected (comma separated)
console.log(`${indices}`);  // 2,5,8,12,17
console.log(`${indices2}`); // 7,11,14,19,22,24
findIndex(str, char) {
    const strLength = str.length;
    const indexes = [];
    let newStr = str;

    while (newStr && newStr.indexOf(char) > -1) {
      indexes.push(newStr.indexOf(char) + strLength- newStr.length);
      newStr = newStr.substring(newStr.indexOf(char) + 1);
    }

    return indexes;
  }

findIndex('scissors', 's'); // [0, 3, 4, 7]
findIndex('Find "s" in this sentence', 's'); // [6, 15, 17]

const findIndices = (str, char) =>
  str.split('').reduce((indices, letter, index) => {
    letter === char && indices.push(index);
    return indices;
  }, [])
findIndices("Hello There!", "e");
// → [1, 8, 10]

findIndices("Looking for new letters!", "o");
// → [1, 2, 9]

const findIndices = (str, char) => str.split('').reduce( (indices, letter, index) => { letter === char && indices.push(index); return indices }, [] );