it-swarm.com.de

Wie überprüfe ich, ob eine Zeichenfolge "StartsWith" eine andere Zeichenfolge ist?

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 .

1636
sol

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:

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
1733
CMS

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:

  • Es wird nicht das gesamte haystack durchsucht.
  • Es wird keine neue temporäre Zeichenfolge erstellt und sofort verworfen.
1262
Mark Byers
data.substring(0, input.length) === input
586
cobbal

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.

182
Vincent

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
57
momomo

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
}
52
Mr.D

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.

38
Kikuchyo

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 mit starts beginnt.

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

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;
}
15
Raj Nathani

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.

11
Scheintod

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

5
Steve Hollasch

Ich habe gerade von dieser String-Bibliothek erfahren:

http://stringjs.com/

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.

2
Ashley Davis
var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
    return true;
else
    return false;
1
Chris
  1. Die Frage ist ein bisschen alt, aber ich wollte diese Antwort schreiben, um Ihnen einige Benchmarks zu zeigen, die ich basierend auf den hier gegebenen Antworten und dem von Jim Buck geteilten jsperf erstellt habe.

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.

1
tonix

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!

0

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.

0
Edward Millen