Frage

Wie würde ich das Äquivalent von C # 's String.StartsWith in JavaScript zu schreiben?

var haystack = 'hello world';
var needle = 'he';

haystack.startsWith(needle) == true

Hinweis: Dies ist eine alte Frage, und wie in den Kommentaren ECMAScript 2015 (ES6) eingeführt, um die .startsWith Methode. Doch zum Zeitpunkt dieses Update des Schreibens (2015) Browser-Unterstützung ist bei weitem nicht vollständig .

War es hilfreich?

Lösung

Sie können mit ECMAScript 6 String.prototype.startsWith() Verfahren, aber es ist noch nicht in allen Browsern unterstützt . Sie erhalten eine Shim / polyfill verwenden möchten es auf Browser hinzufügen, die sie nicht unterstützen. Erstellen einer Implementierung, die mit alle Details gelegt entspricht in die spec ist ein wenig kompliziert. Wenn Sie eine getreue Shim möchten, verwenden Sie entweder:

Wenn Sie die Methode unterfüttert haben (oder wenn Sie nur Browser und JavaScript-Engine unterstützt, die es bereits haben), können Sie es wie folgt verwendet werden:

"Hello World!".startsWith("He"); // true

var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false

Andere Tipps

Eine weitere Alternative mit .lastIndexOf :

haystack.lastIndexOf(needle, 0) === 0

Das sieht rückwärts durch haystack für das Auftreten von needle aus dem Index 0 von haystack starten. Mit anderen Worten, prüft es nur, wenn haystack mit needle beginnt.

Im Prinzip soll diese Performance-Vorteile gegenüber einigen anderen Ansätzen haben:

  • Es wird nicht den gesamten haystack suchen.
  • Sie stellen keine neue temporäre Zeichenfolge erstellen und sie dann sofort verwerfen.
data.substring(0, input.length) === input

Ohne eine Hilfsfunktion, nur regex .test Methode:

/^He/.test('Hello world')

Um dies zu tun, mit einer dynamischen Zeichenfolge anstelle einem hartkodierte eines (unter der Annahme, dass die Zeichenfolge keine regexp Steuerzeichen enthalten):

new RegExp('^' + needle).test(haystack)

Sie sollten überprüfen Gibt es eine Regexp.escape Funktion in Javascript ? , wenn die Möglichkeit besteht, dass regexp Steuerzeichen in der Zeichenfolge erscheinen.

Beste Lösung:

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

Und hier ist endsWith , wenn Sie brauchen, dass auch:

function endsWith(str, word) {
    return str.indexOf(word, str.length - word.length) !== -1;
}

Für diejenigen, die es in String zum Prototyp bevorzugen:

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 hinzuzufügen.

Ich denke, wir können wie folgt 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 zu 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 für den Fall existiert bereits ein zukünftiger Browser es in nativen Code implementiert oder wenn sie von einer anderen Bibliothek implementiert wird. Zum Beispiel führt die Prototype-Bibliothek diese Funktion bereits.

Mit ! ist etwas schneller und prägnanter als === 0 wenn auch nicht so lesbar.

Überprüfen Sie auch underscore.string.js . Es kommt mit einer Reihe von nützlichen Zeichenfolge Testen und Manipulationsverfahren, ein Verfahren, einschließlich startsWith. Aus der Dokumentation:

  

starts _.startsWith(string, starts)

     

Diese Methode überprüft, ob string beginnt mit starts.

_("image.gif").startsWith("image")
=> true

Ich fragte vor kurzem mir die gleiche Frage.
Es gibt mehrere mögliche Lösungen, hier sind 3 gültig diejenigen:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0 (hinzugefügt, nachdem Mark Byers Antwort sehen)
  • 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 habe über die letzte Lösung nicht kommen, die Verwendungen einer Schleife macht.
Überraschenderweise übertrifft diese Lösung die ersten 3 mit deutlichem Vorsprung.
Hier ist der jsperf Test I durchgeführt diese Schlussfolgerung zu erreichen: http://jsperf.com/startswith2/2

Frieden

ps: ECMAScript 6 (Harmonie) stellt eine native startsWith Methode für Streicher
. Man denke nur an, wie viel Zeit gespeichert worden wäre, wenn sie darunter diese dringend benötigte Methode in der ersten Version selbst gedacht hatte.

Aktualisieren

Wie Steve wies darauf hin (der erste Kommentar zu dieser Antwort), die über benutzerdefinierte Funktion einen Fehler aus, wenn die angegebenen Präfix ist kürzer als die gesamte Zeichenfolge. Er hat festgelegt, dass und hat eine Schleife Optimierung, die unter http://jsperf.com/startswith2/4 .

Beachten Sie, dass es 2 Schleifenoptimierungen, die Steve enthalten ist, zeigte die erste der beiden eine bessere Leistung, so werde ich diesen Code schreiben unter:

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, ich denke, es ist beachtenswert, dass es eine Implementierung für diese Methode in ECMA 6 und in Vorbereitung auf diese sollte man den ‚offiziellen‘ polyfill nutzen, um künftige Probleme und Tränen zu verhindern.

Zum Glück sind die Experten von Mozilla geben Sie uns ein:

https://developer.mozilla.org/ de / docs / Web / JavaScript / Reference / Global_Objects / String / starts

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0;
        return this.indexOf(searchString, position) === position;
    };
}

Bitte beachten Sie, dass diese beim Übergang auf ECMA 6 den Vorteil, immer anmutig ignoriert hat.

Die beste performante Lösung ist mit Bibliothek Anrufen zu stoppen und einfach erkennen, dass Sie mit zwei Arrays arbeiten. Eine handgerollte Implementierung ist sowohl kurze und 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;
}

Für Leistungsvergleiche (Erfolg und Misserfolg) finden Sie unter http://jsperf.com/startswith2/4. (Achten Sie darauf, für eine spätere Versionen zu überprüfen, die Mine übertrumpft haben.)

Ich habe gelernt, über diese String-Bibliothek:

http://stringjs.com/

Fügen Sie die JS-Datei und dann die S Variable wie folgt verwenden:

S('hi there').endsWith('hi there')

Es kann auch durch die Installation in NodeJS verwendet werden:

npm install string

Dann ist es als S Variable erforderlich:

var S = require('string');

Die Webseite hat auch Links zu alternativen String-Bibliotheken, wenn diese nicht Ihre Fantasie nimmt.

var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
    return true;
else
    return false;

Auf der Grundlage der Antworten hier, das ist die Version, die ich jetzt bin mit, da es die beste Leistung auf JSPerf Tests auf der Grundlage zu geben scheint (und ist funktional vollständig, soweit ich das beurteilen kann).

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 wurde von hier auf startsWith2 basiert: http://jsperf.com/startswith2/6 . Ich habe eine kleine zwicken für eine winzige Performance-Verbesserung, und habe da auch einen Scheck für den Vergleichsstring hinzugefügt null oder nicht definiert ist, und konvertierte es in dem String-Prototyp mit der Technik in CMS Antwort hinzuzufügen.

Beachten Sie, dass diese Implementierung nicht die „Position“ Parameter unterstützt, die in diesem Mozilla Developer Network Seite, aber das scheint nicht ohnehin Teil des ECMAScript Vorschlag zu sein.

Ich bin nicht sicher, ob der Javascript aber in Typoskript habe ich so etwas wie

var str = "something";
(<String>str).startsWith("some");

Ich denke, es sollte auch auf js arbeiten. Ich hoffe, es hilft!

  1. Die Frage ist ein bisschen alt, aber ich wollte diese Antwort schreiben Sie einige Benchmarks zu zeigen, dass ich auf der Grundlage aller Antworten gemacht hier zur Verfügung gestellt und die jsperf von Jim Buck geteilt.

Ich brauchte im Grunde eine schnelle Art und Weise zu finden, wenn eine lange Nadel in einem Heuhaufen lang ist und sie sind sehr ähnlich, außer für die letzten Zeichen.

Hier ist der Code, den ich geschrieben habe, die für jede Funktion (Spleiß, Teilzeichenfolge, starts, etc.) testet beide, wenn sie zurückkehren falsch und wahr gegen Heuhaufen string (nestedString) von 1.000.0001 Zeichen und einer falsy oder truthy Nadel Zeichenfolge von 1.000.000 Zeichen (testParentStringFalse und testParentStringTrue, respectively):

// 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)
}

I runned diesen Benchmark-Test auf Chrome 75 , Firefox 67 , Safari 12 und Opera 62 .

Ich habe nicht Kanten- und IE enthalten, weil ich sie nicht auf dieser Maschine haben, aber wenn jemand von euch will das Skript für Kanten- und mindestens IE 9 und teilen sich die Ausgabe hier wäre ich sehr gespannt laufen, um zu sehen die Ergebnisse.

Denken Sie daran, dass Sie die 3 langen Strings neu erstellen müssen und das Skript in einer Datei speichern, die Sie dann in Ihrem Browser geöffnet als Kopieren / Einfügen auf der Konsole des Browsers wird es als jede Saite der Länge Block sind> = 1.000.000) .

Hier sind die Ausgänge:

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 für echte Ergebnisse gewinnt, ist auch Safari die schnellste in Bezug auf die Gesamtzeit, um die gesamte Prüfung auszufü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 Siegen Ergebnisse ähnlich sind Chrome und ich bin nicht überrascht, wie Opera auf Chrom 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 jeder Browser seine eigene Implementierungsdetails hat (außer Opera, die auf Chrome Chromium und Blink basiert).

Natürlich weiterer Test mit verschiedenen Anwendungsfällen könnte und soll (zB wenn die Nadel wirklich kurz ist im Vergleich zu Heuhaufen, wenn Heuhaufen kürzer ist als Nadel, etc ...) durchgeführt werden, aber in meinem Fall musste ich sehr vergleichen lange Strings und wollten es hier teilen.

Wenn Sie arbeiten mit startsWith() und endsWith() dann muss man über führende Leerzeichen vorsichtig sein. Hier ist ein komplettes Beispiel:

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

Sie können auch alle Mitglieder eines Arrays zurück, die durch die Erstellung eigener Prototyp / Erweiterung der das Array Prototyp, auch bekannt als

mit einem String starten
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;
};

Und es zu verwenden:

var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top