文字列“ StartsWith”をチェックする方法別の文字列?
-
22-07-2019 - |
質問
C#の String.StartsWith コード>
JavaScriptの場合
var haystack = 'hello world';
var needle = 'he';
haystack.startsWith(needle) == true
注:これは古い質問であり、コメントで指摘されているように、ECMAScript 2015(ES6)は .startsWith
メソッド。ただし、このアップデートの執筆時点(2015)ブラウザのサポートは完全にはほど遠い。
解決
ECMAScript 6の Stringを使用できます。 prototype.startsWith()
メソッド、ただしすべてのブラウザでまだサポートされていません。 shim / polyfillを使用して、それをサポートしていないブラウザーに追加します。 すべての詳細に準拠した実装を作成する仕様は少し複雑です。忠実なシムが必要な場合は、次のいずれかを使用します。
- Matthias Bynensの
String.prototype.startsWith
shim または - es6-shim 。これには、可能な限り多くのES6仕様が含まれます。< code> String.prototype.startsWith 。
メソッドをシム化したら(または、既にサポートしているブラウザーとJavaScriptエンジンのみをサポートしている場合)、次のように使用できます:
"Hello World!".startsWith("He"); // true
var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false
他のヒント
.lastIndexOf を使用した別の代替手段コード>
:
haystack.lastIndexOf(needle, 0) === 0
これは、 haystack
のインデックス 0
から始まる needle
の出現を haystack
で後方に見ていきます。つまり、 haystack
が needle
で始まるかどうかのみをチェックします。
原則として、これには他のいくつかのアプローチよりもパフォーマンス上の利点があります。
-
haystack
全体を検索するわけではありません。 - 新しい一時文字列は作成されず、すぐに破棄されます。
data.substring(0, input.length) === input
ヘルパー関数なしで、正規表現のを使用するだけ .test
メソッド:
/^He/.test('Hello world')
ハードコードされた文字列ではなく、動的な文字列でこれを行うには(文字列に正規表現制御文字が含まれないと仮定します):
new RegExp('^' + needle).test(haystack)
チェックアウトする必要があります JavascriptにRegExp.escape関数があります?文字列に正規表現制御文字が現れる可能性がある場合。
最適なソリューション:
function startsWith(str, word) {
return str.lastIndexOf(word, 0) === 0;
}
startsWith("aaa", "a")
true
startsWith("aaa", "ab")
false
startsWith("abc", "abc")
true
startsWith("abc", "c")
false
startsWith("abc", "a")
true
startsWith("abc", "ba")
false
startsWith("abc", "ab")
true
また、必要な場合は endsWith があります:
function endsWith(str, word) {
return str.indexOf(word, str.length - word.length) !== -1;
}
文字列にプロトタイプを作成したい場合:
String.prototype.startsWith || (String.prototype.startsWith = function(word) {
return this.lastIndexOf(word, 0) === 0;
});
String.prototype.endsWith || (String.prototype.endsWith = function(word) {
return this.indexOf(word, this.length - word.length) !== -1;
});
使用法:
"abc".startsWith("ab")
true
"c".ensdWith("c")
true
これについて自分の意見を加えたかっただけです。
次のように使用できると思います:
var haystack = 'hello world';
var needle = 'he';
if (haystack.indexOf(needle) == 0) {
// Code if string starts with this substring
}
CMSのソリューションに対する小さな改善点は次のとおりです。
if(!String.prototype.startsWith){
String.prototype.startsWith = function (str) {
return !this.indexOf(str);
}
}
"Hello World!".startsWith("He"); // true
var data = "Hello world";
var input = 'He';
data.startsWith(input); // true
将来のブラウザでネイティブコードで実装されている場合、または別のライブラリで実装されている場合に、関数が既に存在するかどうかを確認します。たとえば、プロトタイプライブラリはこの関数を既に実装しています。
!
の使用は、 === 0
よりもわずかに高速で簡潔ですが、読みやすくはありません。
underscore.string.js もご覧ください。 startsWith
メソッドを含む、便利な文字列テストおよび操作メソッドが多数付属しています。ドキュメントから:
startsWith
_。startsWith(string、starts)
このメソッドは、
string
がstarts
で始まるかどうかを確認します。_("image.gif").startsWith("image") => true
最近同じ質問をしました。
考えられる解決策は複数ありますが、有効なものは3つあります:
-
s.indexOf(starter)=== 0
-
s.substr(0、starter.length)=== starter
-
s.lastIndexOf(starter、0)=== 0
(Mark Byersの answer ) -
ループの使用:
function startsWith(s,starter) { for (var i = 0,cur_c; i < starter.length; i++) { cur_c = starter[i]; if (s[i] !== starter[i]) { return false; } } return true; }
ループを使用する最後の解決策に出くわしていません。
驚くべきことに、このソリューションは最初の3つよりもかなりのマージンで優れています。
この結論に到達するために私が実行したjsperfテストは次のとおりです。 http://jsperf.com/startswith2/2
平和
ps:ecmascript 6(harmony)は、文字列にネイティブの startsWith
メソッドを導入します。
初期バージョン自体にこの非常に必要なメソッドを含めることを考えていた場合、どれだけの時間を節約できるかを考えてください。
更新
スティーブが指摘したように(この回答の最初のコメント)、与えられた prefix が文字列全体より短い場合、上記のカスタム関数はエラーをスローします。彼はそれを修正し、 http://jsperf.com/startswith2/4 <で表示できるループ最適化を追加しました。 / a>。
スティーブが含めた2つのループ最適化があることに注意してください。2つのうちの最初のものはより良いパフォーマンスを示したので、そのコードを以下に投稿します。
function startsWith2(str, prefix) {
if (str.length < prefix.length)
return false;
for (var i = prefix.length - 1; (i >= 0) && (str[i] === prefix[i]); --i)
continue;
return i < 0;
}
これは非常に人気があるため、ECMA 6にはこのメソッドの実装があり、その準備として将来の問題と涙を防ぐために「公式」ポリフィルを使用する必要があることを指摘する価値があると思います
幸いなことにMozillaの専門家は私たちに1つを提供します:
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.indexOf(searchString, position) === position;
};
}
これには、ECMA 6への移行時に適切に無視されるという利点があることに注意してください。
最高のパフォーマンスのソリューションは、ライブラリ呼び出しの使用を停止し、2つのアレイで作業していることを認識することです。手巻きの実装は、ここで見た他のすべてのソリューションよりも短いだけでなく、高速です。
function startsWith2(str, prefix) {
if (str.length < prefix.length)
return false;
for (var i = prefix.length - 1; (i >= 0) && (str[i] === prefix[i]); --i)
continue;
return i < 0;
}
パフォーマンスの比較(成功と失敗)については、 http://jsperf.com/startswith2/4。 (私のものよりも後のバージョンを確認してください。)
この文字列ライブラリについて学んだばかりです:
jsファイルを含め、次のように S
変数を使用します。
S('hi there').endsWith('hi there')
NodeJSでインストールすることで使用することもできます:
npm install string
次に、それを S
変数として要求します:
var S = require('string');
ウェブページには、別の文字列ライブラリへのリンクもあります(これがあなたの好みに合わない場合)。
var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
return true;
else
return false;
ここでの回答に基づいて、これは私が現在使用しているバージョンです。JSPerfテストに基づいて最高のパフォーマンスが得られるようです(そして、私が知る限り機能的に完全です)。
if(typeof String.prototype.startsWith != 'function'){
String.prototype.startsWith = function(str){
if(str == null) return false;
var i = str.length;
if(this.length < i) return false;
for(--i; (i >= 0) && (this[i] === str[i]); --i) continue;
return i < 0;
}
}
これは、 http://jsperf.com/startswith2/6 からのstartsWith2に基づいています。わずかなパフォーマンスの改善のために小さな調整を追加し、その後、nullまたは未定義の比較文字列のチェックも追加し、CMSの回答の手法を使用して文字列プロトタイプに追加するように変換しました。
この実装は、「位置」をサポートしていないことに注意してください。この Mozilla開発者ネットワークページですが、それはいずれにせよECMAScript提案の一部ではないようです。
javascriptについてはわかりませんが、typescriptでは次のようなことをしました
var str = "something";
(<String>str).startsWith("some");
jsでも動作するはずです。 役立つことを願っています!
- 質問は少し古いですが、ここで提供されるすべての回答とJim Buckが共有するjsperfに基づいて作成したベンチマークを示すために、この回答を書きたいと思いました。
基本的に、長い針が長い干し草の山の中にあり、最後の文字を除いて非常に似ているかどうかを見つけるための高速な方法が必要でした。
これは、各関数(splice、substring、startsWithなど)が1.000.0001文字のhaystack文字列( nestedString
)に対してfalseとtrueを返すときにテストするコードです。 1.000.000文字の偽または真の針文字列(それぞれ testParentStringFalse
および testParentStringTrue
):
// nestedString is made of 1.000.001 '1' repeated characters.
var nestedString = '...'
// testParentStringFalse is made of 1.000.000 characters,
// all characters are repeated '1', but the last one is '2',
// so for this string the test should return false.
var testParentStringFalse = '...'
// testParentStringTrue is made of 1.000.000 '1' repeated characters,
// so for this string the test should return true.
var testParentStringTrue = '...'
// You can make these very long strings by running the following bash command
// and edit each one as needed in your editor
// (NOTE: on OS X, `pbcopy` copies the string to the clipboard buffer,
// on Linux, you would probably need to replace it with `xclip`):
//
// printf '1%.0s' {1..1000000} | pbcopy
//
function testString() {
let dateStart
let dateEnd
let avg
let count = 100000
const falseResults = []
const trueResults = []
/* slice */
console.log('========> slice')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.slice(0, testParentStringFalse.length) === testParentStringFalse
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
falseResults[falseResults.length] = {
label: 'slice',
avg
}
console.log(`testString() slice = false`, res, 'avg: ' + avg + 'ms')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.slice(0, testParentStringTrue.length) === testParentStringTrue
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
trueResults[trueResults.length] = {
label: 'slice',
avg
}
console.log(`testString() slice = true`, res, 'avg: ' + avg + 'ms')
console.log('<======== slice')
console.log('')
/* slice END */
/* lastIndexOf */
console.log('========> lastIndexOf')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.lastIndexOf(testParentStringFalse, 0) === 0
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
falseResults[falseResults.length] = {
label: 'lastIndexOf',
avg
}
console.log(`testString() lastIndexOf = false`, res, 'avg: ' + avg + 'ms')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.lastIndexOf(testParentStringTrue, 0) === 0
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
trueResults[trueResults.length] = {
label: 'lastIndexOf',
avg
}
console.log(`testString() lastIndexOf = true`, res, 'avg: ' + avg + 'ms')
console.log('<======== lastIndexOf')
console.log('')
/* lastIndexOf END */
/* indexOf */
console.log('========> indexOf')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.indexOf(testParentStringFalse) === 0
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
falseResults[falseResults.length] = {
label: 'indexOf',
avg
}
console.log(`testString() indexOf = false`, res, 'avg: ' + avg + 'ms')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.indexOf(testParentStringTrue) === 0
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
trueResults[trueResults.length] = {
label: 'indexOf',
avg
}
console.log(`testString() indexOf = true`, res, 'avg: ' + avg + 'ms')
console.log('<======== indexOf')
console.log('')
/* indexOf END */
/* substring */
console.log('========> substring')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.substring(0, testParentStringFalse.length) === testParentStringFalse
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
falseResults[falseResults.length] = {
label: 'substring',
avg
}
console.log(`testString() substring = false`, res, 'avg: ' + avg + 'ms')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.substring(0, testParentStringTrue.length) === testParentStringTrue
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
trueResults[trueResults.length] = {
label: 'substring',
avg
}
console.log(`testString() substring = true`, res, 'avg: ' + avg + 'ms')
console.log('<======== substring')
console.log('')
/* substring END */
/* startsWith */
console.log('========> startsWith')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.startsWith(testParentStringFalse)
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
falseResults[falseResults.length] = {
label: 'startsWith',
avg
}
console.log(`testString() startsWith = false`, res, 'avg: ' + avg + 'ms')
dateStart = +new Date()
var res
for (let j = 0; j < count; j++) {
res = nestedString.startsWith(testParentStringTrue)
}
dateEnd = +new Date()
avg = (dateEnd - dateStart)/count
trueResults[trueResults.length] = {
label: 'startsWith',
avg
}
console.log(`testString() startsWith = true`, res, 'avg: ' + avg + 'ms')
console.log('<======== startsWith')
console.log('')
/* startsWith END */
falseResults.sort((a, b) => a.avg - b.avg)
trueResults.sort((a, b) => a.avg - b.avg)
console.log('false results from fastest to slowest avg:', falseResults)
console.log('true results from fastest to slowest avg:', trueResults)
}
このベンチマークテストは、 Chrome 75 、 Firefox 67 、 Safari 12 、および Opera 62 で実行しました。
このマシンにはEdgeとIEがないため、EdgeとIEは含めませんでしたが、もし誰かがEdgeと少なくともIE 9に対してスクリプトを実行し、ここで出力を共有したい場合は、非常に興味があります結果。
3つの長い文字列を再作成し、スクリプトをファイルに保存する必要があることを覚えておいてください。ファイルをブラウザで開くと、ブラウザのコンソールでコピー/貼り付けがブロックされるため、各文字列の長さは&gt; = 1.000.000 )。
出力は次のとおりです。
Chrome 75( substring
が優先):
false results from fastest to slowest avg:
1) {"label":"substring","avg":0.08271}
2) {"label":"slice","avg":0.08615}
3) {"label":"lastIndexOf","avg":0.77025}
4) {"label":"indexOf","avg":1.64375}
5) {"label":"startsWith","avg":3.5454}
true results from fastest to slowest avg:
1) {"label":"substring","avg":0.08213}
2) {"label":"slice","avg":0.08342}
3) {"label":"lastIndexOf","avg":0.7831}
4) {"label":"indexOf","avg":0.88988}
5) {"label":"startsWith","avg":3.55448}
Firefox 67( indexOf
が優先):
false results from fastest to slowest avg
1) {"label":"indexOf","avg":0.1807}
2) {"label":"startsWith","avg":0.74621}
3) {"label":"substring","avg":0.74898}
4) {"label":"slice","avg":0.78584}
5) {"label":"lastIndexOf","avg":0.79668}
true results from fastest to slowest avg:
1) {"label":"indexOf","avg":0.09528}
2) {"label":"substring","avg":0.75468}
3) {"label":"startsWith","avg":0.76717}
4) {"label":"slice","avg":0.77222}
5) {"label":"lastIndexOf","avg":0.80527}
Safari 12( slice
は誤った結果で勝ち、 startsWith
は本当の結果で勝ち、Safariはテスト全体を実行する合計時間の面で最速です):
false results from fastest to slowest avg:
1) "{\"label\":\"slice\",\"avg\":0.0362}"
2) "{\"label\":\"startsWith\",\"avg\":0.1141}"
3) "{\"label\":\"lastIndexOf\",\"avg\":0.11512}"
4) "{\"label\":\"substring\",\"avg\":0.14751}"
5) "{\"label\":\"indexOf\",\"avg\":0.23109}"
true results from fastest to slowest avg:
1) "{\"label\":\"startsWith\",\"avg\":0.11207}"
2) "{\"label\":\"lastIndexOf\",\"avg\":0.12196}"
3) "{\"label\":\"substring\",\"avg\":0.12495}"
4) "{\"label\":\"indexOf\",\"avg\":0.33667}"
5) "{\"label\":\"slice\",\"avg\":0.49923}"
Opera 62( substring
が勝ちます。結果はChromeに似ており、OperaはChromiumとBlinkに基づいているため驚きません):
false results from fastest to slowest avg:
{"label":"substring","avg":0.09321}
{"label":"slice","avg":0.09463}
{"label":"lastIndexOf","avg":0.95347}
{"label":"indexOf","avg":1.6337}
{"label":"startsWith","avg":3.61454}
true results from fastest to slowest avg:
1) {"label":"substring","avg":0.08855}
2) {"label":"slice","avg":0.12227}
3) {"label":"indexOf","avg":0.79914}
4) {"label":"lastIndexOf","avg":1.05086}
5) {"label":"startsWith","avg":3.70808}
すべてのブラウザには独自の実装の詳細があります(ChromeのChromiumとBlinkに基づくOperaを除く)。
もちろん、さまざまなユースケースでさらにテストを実行することができ、実行する必要があります(たとえば、haystackと比較してニードルが本当に短い場合、haystackがニードルより短い場合など)。しかし、私の場合は、長い文字列で、ここで共有したかった。
startsWith()
および endsWith()
を使用している場合は、先頭のスペースに注意する必要があります。完全な例は次のとおりです。
var str1 = " Your String Value Here.!! "; // Starts & ends with spaces
if (str1.startsWith("Your")) { } // returns FALSE due to the leading spaces…
if (str1.endsWith("Here.!!")) { } // returns FALSE due to trailing spaces…
var str2 = str1.trim(); // Removes all spaces (and other white-space) from start and end of `str1`.
if (str2.startsWith("Your")) { } // returns TRUE
if (str2.endsWith("Here.!!")) { } // returns TRUE
また、配列プロトタイプへの独自のプロトタイプ/拡張を作成することで、文字列で始まる配列のすべてのメンバーを返すことができます、別名
Array.prototype.mySearch = function (target) {
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function (str){
return this.slice(0, str.length) == str;
};
}
var retValues = [];
for (var i = 0; i < this.length; i++) {
if (this[i].startsWith(target)) { retValues.push(this[i]); }
}
return retValues;
};
そしてそれを使用するには:
var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium