Comment vérifier si une chaîne "démarre avec" une autre chaîne?

1690

Comment pourrais-je écrire l'équivalent de C # String.StartsWithen JavaScript?

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

haystack.startsWith(needle) == true

Remarque: Il s'agit d'une vieille question et, comme indiqué dans les commentaires, ECMAScript 2015 (ES6) a introduit la .startsWithméthode. Cependant, au moment de la rédaction de cette mise à jour (2015), la prise en charge du navigateur est loin d'être complète .

Luca Kiebel
la source

Réponses:

1773

Vous pouvez utiliser la String.prototype.startsWith()méthode ECMAScript 6 , mais elle n'est pas encore prise en charge dans tous les navigateurs . Vous voudrez utiliser un shim / polyfill pour l'ajouter sur les navigateurs qui ne le prennent pas en charge. La création d'une implémentation conforme à tous les détails énoncés dans la spécification est un peu compliquée. Si vous voulez une cale fidèle, utilisez soit:

Une fois que vous avez modifié la méthode (ou si vous ne supportez que les navigateurs et les moteurs JavaScript qui l'ont déjà), vous pouvez l'utiliser comme ceci:

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

var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false
CMS
la source
@gtournie pourquoi le démarrage serait-il l'une des pires méthodes pour tester si une chaîne commence par une chaîne? (voir votre commentaire ici: stackoverflow.com/questions/646628/… ) vous êtes plus enthousiaste à propos de la comparaison de caractère par caractère. j'espère que les compilateurs sont assez intelligents pour NE PAS générer de chaîne pour chaque chaîne [index] parce que, si vous écrivez simplement ceci: caractère = chaîne [0] il allouera un objet, infiniment MOINS efficace que d'utiliser startWith (démarreWith n'allouera pas de mémoire )
Martijn Scheffer
@MartijnScheffer: La réponse a été modifiée plusieurs fois depuis que j'ai répondu et est maintenant complètement différente (j'ai supprimé mon commentaire;). Je suis d'accord que la méthode startsWith d'ECMAScript 6 est la meilleure façon de le faire.
gtournie
6
@GrahamLaight, lorsque vous dites soutenu par «IE», vous entendez probablement par Edge. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Marcus
@Marcus, excuses si je me trompais - mes informations proviennent de: w3schools.com/jsref/jsref_startswith.asp
Graham Laight
ATTENTION! Ces tests jsperf ne fonctionnent pas dans les navigateurs qui sont bons pour la compilation JIT. Les navigateurs comme Firefox et Chrome le reconnaissent parfois lorsque le résultat d'une opération est ignoré, et n'effectuent donc pas l'opération . En dehors de cela, les moteurs javascript modernes utilisent la prédiction de branche , donc les chaînes de test doivent être différentes à chaque itération.
Aloso
1283

Une autre alternative avec .lastIndexOf:

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

Cela regarde en arrière à travers haystackpour une occurrence de needlepartir de l'index 0de haystack. En d'autres termes, il vérifie uniquement si haystackcommence par needle.

En principe, cela devrait présenter des avantages en termes de performances par rapport à d'autres approches:

  • Il ne recherche pas l'intégralité haystack.
  • Il ne crée pas de nouvelle chaîne temporaire, puis la supprime immédiatement.
Mark Byers
la source
1
Je ne sais pas quel cas @ rfcoder89 prend à propos - jsfiddle.net/jkzjw3w2/1
Gulfaraz Rahman
5
@ rfcoder89 Remarquez que le deuxième paramètre de lastIndexOf: "aba".lastIndexOf ("a")est 2 comme vous le signalez , mais "aba".lastIndexOf ("a", 0)est 0, ce qui est correct
maxpolk
1
Merci beaucoup. String.startsWith ne fonctionne pas sur la sucette Android WebView, mais cet extrait lastIndexOf le fait !!!
Herman
avec lastIndexOf, la chaîne est recherchée de la fin au début afin de rechercher la chaîne entière: ainsi son inefficacité augmente pour les chaînes très longues à rechercher.
willy wonka
8
@willywonka Non, ce n'est pas si vous avez 0 startIndex, il est recherché à partir de 0 pos et c'est la seule vérification. La chaîne entière n'est recherchée que si fromIndex> = str.length.
greene
588
data.substring(0, input.length) === input
cobbal
la source
3
@ANeves Je soupçonne que cela dépend fortement du navigateur et des données utilisées. Voir la réponse de Ben Weaver pour les mesures réelles. Sur le navigateur que j'utilise actuellement (Chrome 12.0.742 sous Windows), la sous-chaîne gagne pour le succès et prépare les regex pour l'échec.
cobbal
4
@cobbal Peut-être. Mais .lastIndexOf(input, 0)compare les N premiers caractères, tandis que le .substring(0, input.length) === inputnombre N, sous-chaîne les données à N longueur, puis compare ces N caractères. À moins d'une optimisation du code, cette deuxième version ne peut pas être plus rapide que l'autre. Ne vous méprenez pas cependant, je ne trouverais jamais par moi-même quelque chose de mieux que ce que vous avez suggéré. :)
ANeves
2
@ANeves Mais .lastIndexOf sur une longue chaîne qui va retourner false va itérer sur toute la chaîne (O (N)), tandis que le cas .substring itère sur une chaîne potentiellement beaucoup plus petite. Si vous vous attendez à des succès majoritaires ou seulement à de petites entrées, .lastIndexOf est probablement plus rapide - sinon .substring est probablement plus rapide. .substring risque également une exception si l'entrée est plus longue que la chaîne vérifiée.
Chris Moschini
14
@ChrisMoschini, n'oubliez pas que la solution de Mark Byers a lastIndexOfcommencé à l'index 0, pas à la fin. Cela m'a aussi fait trébucher au début. Pourtant, vérifier avec quoi commence une chaîne est une tâche si courante que JavaScript devrait vraiment avoir une API appropriée, pas tous les idiomes et alternatives que vous voyez sur cette page, aussi intelligents soient-ils.
Randall Cook
4
Je préfère la solution de cobbal à celle de Mark. Même si la marque est plus rapide et une astuce impressionnante en utilisant les paramètres, elle est très difficile à lire par rapport à la sous-chaîne.
ThinkBonobo
184

Sans fonction d'assistance, il suffit d'utiliser la .testméthode de regex :

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

Pour ce faire avec une chaîne dynamique plutôt qu'une chaîne codée en dur (en supposant que la chaîne ne contiendra aucun caractère de contrôle regexp):

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

Vous devriez vérifier Y a-t-il une fonction RegExp.escape en Javascript? si la possibilité existe que des caractères de contrôle d'expression rationnelle apparaissent dans la chaîne.

Vincent
la source
1
Afin de rendre l'expression sensible à la casse/^he/i
kaizer1v
64

Meilleure solution:

function startsWith(str, word) {
    return str.lastIndexOf(word, 0) === 0;
}

Et voici la fin Avec si vous en avez besoin aussi:

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

Pour ceux qui préfèrent le prototyper en String:

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

Usage:

"abc".startsWith("ab")
true
"c".ensdWith("c") 
true

Avec méthode:

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
mmm
la source
Je pense que vous avez mélangé lastIndexOf et indexOf dans vos fonctions - startsWith devrait être return str.indexOf (word, 0) === 0;
Richard Matheson
5
@RichardMatheson le problème avec l'utilisation d'indexOf est que s'il échoue la correspondance au début, il continuera à rechercher la chaîne entière, où lastIndexOf commence à partir de la longueur du mot et revient à zéro. Je l'ai?
mmm
2
Ahh oui, c'est logique maintenant - je n'ai pas prêté attention aux indices que vous utilisiez. Très bon truc!
Richard Matheson
54

Je voulais juste ajouter mon opinion à ce sujet.

Je pense que nous pouvons simplement utiliser comme ceci:

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

if (haystack.indexOf(needle) == 0) {
  // Code if string starts with this substring
}
Mr.D
la source
2
La réponse de Mark Byers a été comparée pour les performances de trois approches correctes différentes par @relfor. Cette approche correcte n'a pas été privilégiée car elle nécessite de rechercher la chaîne entière.
maxpolk
@maxpolk, je pense indexOf, arrêtera de rechercher la chaîne entière quand il trouvera la première occurrence. Je l'ai vérifié.
M.D
8
Si la première occurrence n'est pas trouvée au tout début, cette approche commence à devenir inefficace au fur et à mesure qu'elle continue à le rechercher, potentiellement à la recherche jusqu'à la fin, au lieu d'abandonner beaucoup plus tôt. Parce qu'il existe un potentiel d'inefficacité, il n'est pas privilégié parmi les trois bonnes approches.
maxpolk
2
@ Mr.D Et s'il n'y a pas de correspondance?
mmm
sinon quand toute la botte de foin a été fouillée? c'est mieux: stackoverflow.com/a/36876507/961018 .. recherche uniquement jusqu'à la longueur du mot
mmm
39

Voici une amélioration mineure à la solution de 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

Vérifier si la fonction existe déjà dans le cas où un futur navigateur l'implémenterait en code natif ou si elle est implémentée par une autre bibliothèque. Par exemple, la bibliothèque de prototypes implémente déjà cette fonction.

L'utilisation !est légèrement plus rapide et plus concise que === 0si elle n'est pas aussi lisible.

Trousse
la source
1
Cela pourrait devenir un problème: si l'implémentation déjà en place se comporte différemment de la mienne, cela briserait mon application.
Christoph Wurm
2
Cela a le problème O (N) discuté ici stackoverflow.com/questions/646628/javascript-startswith/…
Chris Moschini
1
en utilisant ! il y a très désordonné
JonnyRaa
-1; l'ajouter à String.prototypeest une mauvaise idée car il ne se rapproche pas du respect des spécifications pour String.prototype.startsWith. Tout code qui essaie d'utiliser la méthode ES6 est susceptible d'échouer si vous faites cela; il peut bien chercher à voir si la méthode est déjà définie, voir qu'elle l'est (mal, par vous) et ne pas ajouter de shim conforme aux spécifications, conduisant à un comportement incorrect plus tard.
Mark Amery
21

Consultez également underscore.string.js . Il est livré avec un tas de méthodes de test et de manipulation de chaînes utiles, dont une startsWithméthode. De la documentation:

commence avec _.startsWith(string, starts)

Cette méthode vérifie si string commence par starts.

_("image.gif").startsWith("image")
=> true
studgeek
la source
1
J'avais besoin_.string.startsWith
Colonel Panic
15

Je me suis récemment posé la même question.
Il existe plusieurs solutions possibles, en voici 3 valides:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0(ajouté après avoir vu la réponse de Mark Byers )
  • en utilisant une boucle:

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

Je n'ai pas trouvé la dernière solution qui utilise une boucle.
Étonnamment, cette solution surpasse les 3 premiers d'une marge significative.
Voici le test jsperf que j'ai effectué pour arriver à cette conclusion: http://jsperf.com/startswith2/2

Paix

ps: ecmascript 6 (harmonie) introduit une startsWithméthode native pour les chaînes.
Imaginez combien de temps aurait été gagné s'ils avaient pensé à inclure cette méthode si nécessaire dans la version initiale elle-même.

Mise à jour

Comme Steve l'a souligné (le premier commentaire sur cette réponse), la fonction personnalisée ci-dessus générera une erreur si le préfixe donné est plus court que la chaîne entière. Il a corrigé cela et ajouté une optimisation de boucle qui peut être consultée sur http://jsperf.com/startswith2/4 .

Notez qu'il y a 2 optimisations de boucle que Steve a incluses, la première des deux a montré de meilleures performances, donc je posterai ce code ci-dessous:

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;
}
Raj Nathani
la source
Voir la dernière rév. Outre le bogue de la version ci-dessus (il lancera si la chaîne est plus courte que le préfixe), il est également plus lent qu'une version plus optimisée. Voir jsperf.com/startswith2/4 et jsperf.com/js-startswith/35 .
Steve Hollasch
^ Merci d'avoir signalé le cas où la chaîne est plus courte que le préfixe
Raj Nathani
jsperf.com/startswith2/29 => startsWith5 est concis et fonctionne très bien =)
gtournie
11

Étant donné que cela est si populaire, je pense qu'il convient de souligner qu'il existe une implémentation de cette méthode dans ECMA 6 et qu'en préparation, il convient d'utiliser le polyfill `` officiel '' afin d'éviter de futurs problèmes et larmes.

Heureusement, les experts de Mozilla nous en fournissent un:

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

Veuillez noter que cela a l'avantage d'être ignoré avec élégance lors de la transition vers ECMA 6.

Scheintod
la source
5

La solution la plus performante consiste à cesser d'utiliser les appels de bibliothèque et à reconnaître simplement que vous travaillez avec deux tableaux. Une implémentation roulée à la main est à la fois courte et aussi plus rapide que toutes les autres solutions que j'ai vues ici.

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

Pour des comparaisons de performances (succès et échec), voir http://jsperf.com/startswith2/4 . (Assurez-vous de vérifier les versions ultérieures qui peuvent avoir trompé la mienne.)

Steve Hollasch
la source
2

Je viens d'apprendre cette bibliothèque de chaînes:

http://stringjs.com/

Incluez le fichier js, puis utilisez la Svariable comme ceci:

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

Il peut également être utilisé dans NodeJS en l'installant:

npm install string

Le nécessitant ensuite comme Svariable:

var S = require('string');

La page Web contient également des liens vers d'autres bibliothèques de chaînes, si celle-ci ne vous convient pas.

Ashley Davis
la source
2
  1. La question est un peu ancienne, mais je voulais écrire cette réponse pour vous montrer quelques repères que j'ai faits sur la base de toutes les réponses fournies ici et du jsperf partagé par Jim Buck.

J'avais essentiellement besoin d'un moyen rapide pour savoir si une longue aiguille se trouve dans une longue botte de foin et elles sont très similaires, sauf pour les derniers caractères.

Voici le code que j'ai écrit qui pour chaque fonction (épissure, sous-chaîne, démarre avec, etc.) teste à la fois quand ils retournent faux et vrai contre une chaîne de botte de foin ( nestedString) de 1.000.0001 caractères et une chaîne d'aiguille fausse ou véridique de 1.000.000 caractères ( testParentStringFalseet testParentStringTrue, respectivement):

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

J'ai exécuté ce test de référence sur Chrome 75 , Firefox 67 , Safari 12 et Opera 62 .

Je n'ai pas inclus Edge et IE car je ne les ai pas sur cette machine, mais si quelqu'un d'entre vous veut exécuter le script contre Edge et au moins IE 9 et partager la sortie ici, je serais très curieux de voir les résultats.

N'oubliez pas que vous devez recréer les 3 longues chaînes et enregistrer le script dans un fichier que vous ouvrez ensuite dans votre navigateur car le copier / coller sur la console du navigateur le bloquera car la longueur de chaque chaîne est> = 1.000.000).

Voici les sorties:

Chrome 75 ( substringgagne):

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 ( indexOfgagne):

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 ( slicegagne pour de faux résultats, startsWithgagne pour de vrais résultats, Safari est également le plus rapide en termes de temps total pour exécuter l'ensemble du test):

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 ( substringvictoires. Les résultats sont similaires à Chrome et je ne suis pas surpris car Opera est basé sur Chrome et 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}

Il s'avère que chaque navigateur a ses propres détails d'implémentation (à l'exception d'Opera, qui est basé sur Chrome et Blink de Chrome).

Bien sûr, un test supplémentaire avec différents cas d'utilisation pourrait et devrait être effectué (par exemple, lorsque l'aiguille est vraiment courte par rapport à la botte de foin, lorsque la botte de foin est plus courte que l'aiguille, etc.), mais dans mon cas, je devais comparer de très longues cordes et voulait le partager ici.

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

Sur la base des réponses ici, c'est la version que j'utilise maintenant, car elle semble donner les meilleures performances basées sur les tests JSPerf (et est fonctionnellement complète pour autant que je sache).

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

Ceci était basé sur startsWith2 à partir d'ici: http://jsperf.com/startswith2/6 . J'ai ajouté un petit ajustement pour une amélioration minime des performances, et depuis j'ai également ajouté une vérification pour que la chaîne de comparaison soit nulle ou non définie, et je l'ai convertie pour l'ajouter au prototype String en utilisant la technique dans la réponse de CMS.

Notez que cette implémentation ne prend pas en charge le paramètre "position" qui est mentionné dans cette page Mozilla Developer Network , mais qui ne semble pas faire partie de la proposition ECMAScript de toute façon.

Edward Millen
la source
0

Je ne suis pas sûr pour javascript mais en tapuscrit j'ai fait quelque chose comme

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

Je suppose que cela devrait aussi fonctionner sur js. J'espère que ça aide!

Andreas Hadjithoma
la source
-2

Si vous travaillez avec startsWith()et endsWith()alors vous devez faire attention aux espaces de tête. Voici un exemple complet:

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
immayankmodi
la source
3
C'est un comportement très non standard: la chaîne "abc" ne commence PAS par "abc". Plus précisément, ECMA 6 n'assume aucune sorte de coupe de chaîne, de sorte que les espaces blancs doivent correspondre exactement pour produire une correspondance startWith.
Steve Hollasch
3
Comment ... comment cela répond-il à la question?
DCShannon
1
@DCShannon ce n'est pas le cas. C'est un non-sens incompréhensible.
Mark Amery
2
@SteveHollasch Mon intention était de sensibiliser tous ceux qui recherchaient le même problème que moi. Que nous devons être prudents avec les espaces de tête lors de l'utilisation startsWith()et des endsWith()fonctions. Rien d'autre!
immayankmodi
-3

Vous pouvez également renvoyer tous les membres d'un tableau commençant par une chaîne en créant votre propre prototype / extension au prototype du tableau, alias

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

Et pour l'utiliser:

var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium
Nepaluz
la source