web-dev-qa-db-ja.com

JavaScriptで別の文字列のすべての出現のインデックスを見つける方法は?

私は、大文字と小文字を区別しない、別の文字列内の文字列のすべての出現の位置を見つけようとしています。

たとえば、次の文字列を指定します。

レバノンでウクレレを弾くことを学びました。

検索文字列le、配列を取得したい:

_[2, 25, 27, 33]
_

両方の文字列は変数になります-つまり、値をハードコーディングできません。

これは正規表現の簡単なタスクだと思いましたが、しばらくの間、うまくいくものを見つけるのに苦労した後、私は運がありませんでした。

私は この例.indexOf()を使用してこれを達成する方法を見つけましたが、確かにそれを行うためのより簡潔な方法が必要ですか?

77
Bungle
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);
}

[〜#〜] 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 + "";
<div id="output"></div>
132
Tim Down

正規表現の無料版は次のとおりです。

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")

[〜#〜] edit [〜#〜]:「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;
}
15
jcubic

あなたは確かにこれを行うことができます!

//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記述 では、実際にこのオブジェクトをかなり詳細に記述しています。

12
Ryley

すべてのマッチの位置を見つけたいだけなら、ちょっとしたハックを教えてください。

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)

可変長のRegExpがある場合は適切ではないかもしれませんが、一部の人にとっては役立つかもしれません。

2
Hoffmann

String.prototype.match を使用します。

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']
1
tejasbubane

@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;
}
0

これは簡単なコードです

function getIndexOfSubStr(str, serchToken, preIndex, output){
                 var result = str.match(serchToken);
     if(result){
     output.Push(result.index +preIndex);
     str=str.substring(result.index+serchToken.length);
     getIndexOfSubStr(str, serchToken, preIndex, output)
     }
     return output;
  };

var str = "my name is 'xyz' and my school name is 'xyz' and my area name is 'xyz' ";
var  serchToken ="my";
var preIndex = 0;

console.log(getIndexOfSubStr(str, serchToken, preIndex, []));
0
Kapil Tiwari

すべての返信をありがとう。私はそれらをすべて調べて、「needle」部分文字列の各出現の最初の最後のインデックスを与える関数を考え出しました。誰かを助けるためにここに投稿しています。

各オカレンスの先頭のみに対する元のリクエストと同じではないことに注意してください。針の長さを維持する必要がないので、私のユースケースにより適しています。

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
}
0
Roei Bahumi