Wie würde ich das Äquivalent von C # String.StartsWith
in JavaScript schreiben?
_var haystack = 'hello world';
var needle = 'he';
haystack.startsWith(needle) == true
_
Hinweis: Dies ist eine alte Frage. Wie in den Kommentaren erläutert, führte ECMAScript 2015 (ES6) die Methode .startsWith
ein. Zum Zeitpunkt des Schreibens dieses Updates (2015) Browser-Unterstützung ist bei weitem nicht vollständig .
Sie können die Methode String.prototype.startsWith()
von ECMAScript 6 verwenden, sie wird jedoch noch nicht in allen Browsern unterstützt. Sie sollten ein Shim/Polyfill verwenden, um es in Browsern hinzuzufügen, die es nicht unterstützen. Das Erstellen einer Implementierung, die allen in der Spezifikation angegebenen Details entspricht, ist etwas kompliziert. Wenn Sie eine zuverlässige Unterlage wünschen, verwenden Sie entweder:
String.prototype.startsWith
Shim , oderString.prototype.startsWith
.Sobald Sie die Methode angepasst haben (oder wenn Sie nur Browser und JavaScript-Engines unterstützen, die sie bereits haben), können Sie sie folgendermaßen verwenden:
"Hello World!".startsWith("He"); // true
var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false
Eine weitere Alternative mit .lastIndexOf
:
_haystack.lastIndexOf(needle, 0) === 0
_
Dies durchsucht haystack
rückwärts nach einem Vorkommen von needle
, beginnend mit dem Index _0
_ von haystack
. Mit anderen Worten, es wird nur geprüft, ob haystack
mit needle
beginnt.
Grundsätzlich sollte dies Leistungsvorteile gegenüber einigen anderen Ansätzen haben:
haystack
durchsucht.data.substring(0, input.length) === input
Verwenden Sie ohne Hilfsfunktion einfach die .test
-Methode von Regex:
_/^He/.test('Hello world')
_
Gehen Sie dazu mit einer dynamischen Zeichenfolge anstelle einer fest codierten Zeichenfolge vor (vorausgesetzt, die Zeichenfolge enthält keine regulären Ausdruckssteuerzeichen):
_new RegExp('^' + needle).test(haystack)
_
Sie sollten auschecken Gibt es eine RegExp.escape-Funktion in Javascript? wenn die Möglichkeit besteht, dass Regexp-Steuerzeichen in der Zeichenfolge angezeigt werden.
Beste Lösung:
function startsWith(str, Word) {
return str.lastIndexOf(Word, 0) === 0;
}
Benutzt:
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
Und hier ist endsWith wenn du das auch brauchst:
function endsWith(str, Word) {
return str.indexOf(Word, str.length - Word.length) !== -1;
}
Für diejenigen, die es vorziehen, es in String zu prototypisieren:
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;
});
Verwendung:
"abc".startsWith("ab")
true
"c".ensdWith("c")
true
Ich wollte nur meine Meinung dazu hinzufügen.
Ich denke, wir können einfach so verwenden:
var haystack = 'hello world';
var needle = 'he';
if (haystack.indexOf(needle) == 0) {
// Code if string starts with this substring
}
Hier ist eine kleine Verbesserung der CMS-Lösung:
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
Überprüfen, ob die Funktion bereits vorhanden ist, falls ein zukünftiger Browser sie in systemeigenen Code implementiert oder von einer anderen Bibliothek implementiert wird. Beispielsweise implementiert die Prototype Library diese Funktion bereits.
Die Verwendung von !
ist etwas schneller und präziser als die von === 0
, jedoch nicht so gut lesbar.
Schauen Sie sich auch nderscore.string.js an. Es wird mit einer Reihe nützlicher Methoden zum Testen und Bearbeiten von Zeichenfolgen geliefert, einschließlich einer startsWith
-Methode. Aus den Dokumenten:
startsWith
_.startsWith(string, starts)
Diese Methode prüft, ob
string
mitstarts
beginnt._("image.gif").startsWith("image") => true
Ich habe mir vor kurzem die gleiche Frage gestellt.
Es gibt mehrere mögliche Lösungen, hier sind 3 gültige:
s.indexOf(starter) === 0
s.substr(0,starter.length) === starter
s.lastIndexOf(starter, 0) === 0
(hinzugefügt, nachdem Mark Byers's answer )mit einer Schleife:
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;
}
Ich bin nicht auf die letzte Lösung gestoßen, die eine Schleife nutzt.
Überraschenderweise übertrifft diese Lösung die ersten 3 um ein Vielfaches.
Hier ist der jsperf-Test, den ich durchgeführt habe, um zu dieser Schlussfolgerung zu gelangen: http://jsperf.com/startswith2/2
Frieden
ps: ecmascript 6 (harmony) führt eine native startsWith
-Methode für Zeichenfolgen ein.
Stellen Sie sich vor, wie viel Zeit gespart worden wäre, wenn Sie daran gedacht hätten, diese dringend benötigte Methode in die ursprüngliche Version selbst aufzunehmen.
Update
Wie Steve ausführte (der erste Kommentar zu dieser Antwort), wird die oben genannte benutzerdefinierte Funktion einen Fehler auslösen, wenn das angegebene Präfix kürzer als die gesamte Zeichenfolge ist. Er hat das behoben und eine Schleifenoptimierung hinzugefügt, die unter http://jsperf.com/startswith2/4 eingesehen werden kann.
Beachten Sie, dass Steve zwei Loop-Optimierungen einbezogen hat, von denen die erste eine bessere Leistung gezeigt hat. Daher werde ich den folgenden Code veröffentlichen:
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;
}
Da dies so beliebt ist, sollte ich darauf hinweisen, dass es eine Implementierung für diese Methode in ECMA 6 gibt, und in Vorbereitung darauf sollte die "offizielle" Polyfüllung verwendet werden, um zukünftige Probleme und Risse zu vermeiden.
Zum Glück stellen uns die Experten von Mozilla eines zur Verfügung:
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.indexOf(searchString, position) === position;
};
}
Bitte beachten Sie, dass dies den Vorteil hat, dass der Übergang zu ECMA 6 ordnungsgemäß ignoriert wird.
Die leistungsfähigste Lösung besteht darin, keine Bibliotheksaufrufe mehr zu verwenden und nur zu erkennen, dass Sie mit zwei Arrays arbeiten. Eine handgerollte Implementierung ist sowohl kurz als auch schneller als jede andere Lösung, die ich hier gesehen habe.
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;
}
Leistungsvergleiche (Erfolg und Misserfolg) finden Sie unter http://jsperf.com/startswith2/4 . (Stellen Sie sicher, dass Sie nach neueren Versionen suchen, die meine möglicherweise übertroffen haben.)
Ich habe gerade von dieser String-Bibliothek erfahren:
Schließen Sie die js-Datei ein und verwenden Sie dann die Variable S
wie folgt:
S('hi there').endsWith('hi there')
Es kann auch in NodeJS verwendet werden, indem es installiert wird:
npm install string
Dann benötigen Sie es als S
-Variable:
var S = require('string');
Die Webseite enthält auch Links zu alternativen String-Bibliotheken, falls Sie dies nicht wünschen.
var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
return true;
else
return false;
Grundsätzlich brauchte ich einen schnellen Weg, um herauszufinden, ob sich eine lange Nadel in einem langen Heuhaufen befindet und sie bis auf die letzten Zeichen sehr ähnlich sind.
Hier ist der von mir geschriebene Code, der für jede Funktion (Spleiß, Teilzeichenfolge, Starts mit usw.) prüft, ob sie false und true für eine Heuhaufenzeichenfolge (nestedString
) mit 1.000.0001 Zeichen und eine falsche oder echte Nadel zurückgeben Zeichenfolge mit 1.000.000 Zeichen (testParentStringFalse
bzw. 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)
}
Ich habe diesen Benchmarktest mit Chrome 75, Firefox 67, Safari 12 und Opera 62 durchgeführt.
Ich habe Edge und IE nicht eingeschlossen, weil ich sie nicht auf diesem Computer habe, aber wenn jemand von Ihnen das Skript gegen Edge und mindestens IE 9 ausführen und das freigeben möchte hier auszugeben wäre ich sehr gespannt auf die ergebnisse.
Denken Sie daran, dass Sie die 3 langen Zeichenfolgen neu erstellen und das Skript in einer Datei speichern müssen, die Sie dann in Ihrem Browser öffnen, da das Kopieren/Einfügen auf der Browserkonsole dies blockiert, da die Länge jeder Zeichenfolge> = 1.000.000 ist.
Hier sind die Ausgaben:
Chrome 75 (substring
gewinnt):
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
gewinnt):
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
gewinnt für falsche Ergebnisse, startsWith
gewinnt für echte Ergebnisse, auch Safari ist in Bezug auf die Gesamtzeit die schnellste, um den gesamten Test durchzuführen):
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
gewinnt. Die Ergebnisse ähneln Chrome und ich bin nicht überrascht, da Opera auf Chromium und Blink basiert):
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}
Es stellt sich heraus, dass jeder Browser seine eigenen Implementierungsdetails hat (abgesehen von Opera, das auf Chromium und Blink von Chrome basiert).
Natürlich könnte und sollte ein weiterer Test mit verschiedenen Anwendungsfällen durchgeführt werden (z. B. wenn die Nadel im Vergleich zum Heuhaufen wirklich kurz ist, wenn der Heuhaufen kürzer als die Nadel ist usw.), aber in meinem Fall musste ich sehr lange Saiten und vergleichen wollte es hier teilen.
Ich bin mir für Javascript nicht sicher, aber in TypeScript habe ich so etwas gemacht
var str = "something";
(<String>str).startsWith("some");
Ich denke, es sollte auch bei js funktionieren. Ich hoffe, es hilft!
Basierend auf den Antworten hier ist dies die Version, die ich jetzt verwende, da sie die beste Leistung auf der Grundlage von JSPerf-Tests zu bieten scheint (und soweit ich das beurteilen kann, funktionsfähig ist).
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;
}
}
Dies basierte auf startsWith2 von hier: http://jsperf.com/startswith2/6 . Ich habe einen kleinen Tweak hinzugefügt, um die Leistung geringfügig zu verbessern, und seitdem auch eine Überprüfung für die Vergleichszeichenfolge hinzugefügt, die null oder undefiniert ist, und sie konvertiert, um sie unter Verwendung der in der Antwort von CMS beschriebenen Technik zum String-Prototyp hinzuzufügen.
Beachten Sie, dass diese Implementierung den auf dieser Seite Mozilla Developer Network erwähnten Parameter "position" nicht unterstützt, aber das scheint ohnehin nicht Teil des ECMAScript-Vorschlags zu sein.