Подтвердить что ты не робот

Поиск всех индексов заданного символа внутри строки

Например, если я имел "scissors" в переменной и хотел знать положение всех вхождений буквы "s", он должен распечатать 1, 4, 5, 8

Как я могу сделать это в JavaScript наиболее эффективным способом? Я не думаю, что цикл через все ужасно эффективен

4b9b3361

Ответ 1

Простой цикл работает хорошо:

var str = "scissors";
var indices = [];
for(var i=0; i<str.length;i++) {
    if (str[i] === "s") indices.push(i);
}

Теперь вы указываете, что хотите 1,4,5,8. Это даст вам 0, 3, 4, 7, поскольку индексы основаны на нуле. Таким образом, вы можете добавить один:

if (str[i] === "s") indices.push(i+1);

и теперь он даст вам ожидаемый результат.

Скрипку можно увидеть здесь.

Я не думаю, что цикл через все ужасно эффективен

Что касается производительности, я не думаю, что это то, о чем вам нужно серьезно беспокоиться, пока вы не начнете сталкиваться с проблемами.

Вот тест jsPerf, сравнивающий различные ответы. В Safari 5.1 IndexOf работает лучше всего. В Chrome 19 цикл for является самым быстрым.

enter image description here

Ответ 2

С помощью встроенного метода String.prototype.indexOf наиболее эффективно найти каждое смещение.

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!

Graph of performance results from the link

Ответ 3

benchmark

Когда я сравнивал все, что казалось, что регулярные выражения выполняются лучше всего, поэтому я придумал этот

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]}

таким образом вы можете получить все индексы ваших совпадений за один раз

Ответ 4

function charPos(str, char) {
  return str
         .split("")
         .map(function (c, i) { if (c == char) return i; })
         .filter(function (v) { return v >= 0; });
}

charPos("scissors", "s");  // [0, 3, 4, 7]

Обратите внимание, что JavaScript рассчитывается с 0. Добавьте +1 в i, если нужно.

Ответ 5

Более функциональное удовольствие, а также более общее: это находит начальные индексы подстроки любой длины в строке

const length = (x) => x.length
const sum = (a, b) => a+b

const indexesOf = (substr) => ({
  in: (str) => (
    str
    .split(substr)
    .slice(0, -1)
    .map(length)
    .map((_, i, lengths) => (
      lengths
      .slice(0, i+1)
      .reduce(sum, i*substr.length)
    ))
  )  
});

console.log(indexesOf('s').in('scissors')); // [0,3,4,7]

console.log(indexesOf('and').in('a and b and c')); // [2,8]

Ответ 6

indices = (c, s) => s
          .split('')
          .reduce((a, e, i) => e === c ? a.concat(i) : a, []);

indices('?', 'a?g??'); // [1, 3, 4]

Ответ 7

Вы также можете использовать функцию match() в javascript. Вы можете создать регулярное выражение и затем передать его в качестве параметра в match().

stringName.match(/s/g);

Это должно вернуть вам массив всех вхождений буквы 's'.

Ответ 8

Мне понравился вопрос, и я решил написать свой ответ, используя метод 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