Existe-t-il une méthode d'épissure pour les chaînes?

87

Le Javascript splicene fonctionne qu'avec des tableaux. Existe-t-il une méthode similaire pour les chaînes? Ou devrais-je créer ma propre fonction personnalisée?

Les méthodes substr(), et substring()renverront uniquement la chaîne extraite et ne modifieront pas la chaîne d'origine. Ce que je veux faire, c'est supprimer une partie de ma chaîne et appliquer la modification à la chaîne d'origine. De plus, la méthode replace()ne fonctionnera pas dans mon cas car je souhaite supprimer des parties en commençant par un index et se terminant à un autre index, exactement comme ce que je peux faire avec la splice()méthode. J'ai essayé de convertir ma chaîne en tableau, mais ce n'est pas une bonne méthode.

ProllyGeek
la source
str.splitpeut-être la fonction que vous recherchez: google.com/#q=javascript+string+split
Anderson Green
1
Quel est le problème avec str = str.slice()?
elclanrs
1
Cela ressemble à un problème XY, qu'essayez-vous de faire exactement? Les chaînes ne sont pas passées par référence, contrairement aux tableaux et aux objets, vous ne faites donc pas muter les chaînes, vous en créez de nouvelles ou en réassignez la nouvelle à l'ancienne.
elclanrs
1
duplication possible de Set String via la fonction String.prototype sans retour
raina77ow
6
return string.slice(0, startToSplice) + string.slice(endToSplice);, non?
raina77ow

Réponses:

88

Il est plus rapide de couper la chaîne deux fois, comme ceci:

function spliceSlice(str, index, count, add) {
  // We cannot pass negative indexes directly to the 2nd slicing operation.
  if (index < 0) {
    index = str.length + index;
    if (index < 0) {
      index = 0;
    }
  }

  return str.slice(0, index) + (add || "") + str.slice(index + count);
}

que d'utiliser un fractionnement suivi d'une jointure (méthode de Kumar Harsh), comme ceci:

function spliceSplit(str, index, count, add) {
  var ar = str.split('');
  ar.splice(index, count, add);
  return ar.join('');
}

Voici un jsperf qui compare les deux méthodes et quelques autres. (jsperf est en panne depuis quelques mois maintenant. Veuillez suggérer des alternatives dans les commentaires.)

Bien que le code ci-dessus implémente des fonctions qui reproduisent la fonctionnalité générale de splice, l'optimisation du code pour le cas présenté par le demandeur (c'est-à-dire, n'ajouter rien à la chaîne modifiée) ne change pas les performances relatives des différentes méthodes.

Louis
la source
3
Vous pouvez l'ajouter globalement avec: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Gardez simplement à l'esprit que cela ne fonctionne pas exactement de la même manière que la méthode d'épissure de tableau car les chaînes sont immuables (vous ne pouvez pas les modifier une fois créées). Donc, l'utilisation serait comme:var s="ss"; s = s.splice(0,1,"t");
William Neely
@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};serait standard pour la manipulation de chaînes car vous avez dit qu'elle est immuable.
M. Polywhirl
spliceSlice et spliceSplit ne sont pas fonctionnellement égaux car Array.prototype.splice accepte les indices négatifs: jsfiddle.net/sykteho6/5 .
Martijn le
1
@Mzialla Merci, j'ai ajouté du code pour m'en occuper.
Louis le
Créer des variables temporaires et introduire des emplacements pour les erreurs ponctuelles, sans parler du code qui prend plus de temps pour les humains à traiter par opposition à split (""). Splice (...). Join ("") est un compromis qui mérite considération. Le problème de la vitesse n'est un problème que s'il s'agit d'un problème.
Ben Fletcher
15

Éditer

Ce n'est bien sûr pas la meilleure façon d '"épisser" une chaîne, j'avais donné ceci comme exemple de la façon dont l'implémentation serait, ce qui est imparfait et très évident à partir d'un split (), splice () et join (). Pour une mise en œuvre bien meilleure, voir la méthode de Louis .


Non, il n'existe pas de a String.splice, mais vous pouvez essayer ceci:

newStr = str.split(''); // or newStr = [...str];
newStr.splice(2,5);
newStr = newStr.join('');

Je me rends compte qu'il n'y a pas de splicefonction comme dans les tableaux, vous devez donc convertir la chaîne en un tableau. Pas de veine...

Kumarharsh
la source
dans mon cas, je travaille sur une chaîne dynamique, je dois donc spécifier des indices et non une valeur de caractère.
ProllyGeek
Oui, c'est malheureusement correct. Mais vous pouvez obtenir l'index d'un caractère en utilisant String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh
3
Au lieu d'utiliser str.split, vous pouvez utiliser la syntaxe de diffusion ES6 comme ceci:[...str]
robbie
5

Voici un joli petit curry qui donne une meilleure lisibilité (IMHO):

La signature de la deuxième fonction est identique à la Array.prototype.spliceméthode.

function mutate(s) {
    return function splice() {
        var a = s.split('');
        Array.prototype.splice.apply(a, arguments);
        return a.join('');
    };
}

mutate('101')(1, 1, '1');

Je sais qu'il existe déjà une réponse acceptée, mais j'espère que cela sera utile.

Cody
la source
1
Np. Vous pouvez même faire abstraction de cela pour autoriser, par exemple, un 'method'paramètre facultatif afin que vous puissiez passer un Array.prototype[method]et traiter les chaînes comme des tableaux. De plus, avec celui - ci seul, vous pourriez abstraire le processus réel à une autre fonction - et s'il n'y a pas de chaîne, le retour d' une fonction qui prendra la chaîne et d' inverser le curry: mutate()(1, 1, '1')('101'); Vous pouvez même duckType les arguments pour débarrasser le curry de l'invocation vide - même encapsuler une méthode, elle-même. Si vous avez besoin de ce matériel, vous voudrez peut-être examiner le modèle de commande . Juste des crachats ici.
Cody
3

Je voudrais proposer une alternative plus simple aux méthodes Kumar / Cody et Louis. Sur tous les tests que j'ai effectués, il fonctionne aussi vite que la méthode Louis (voir les tests de violon pour les benchmarks).

String.prototype.splice = function(startIndex,length,insertString){
    return this.substring(0,startIndex) + insertString + this.substring(startIndex + length);
};

Vous pouvez l'utiliser comme ceci:

var creditCardNumber = "5500000000000004";
var cardSuffix = creditCardNumber.splice(0,12,'****');
console.log(cardSuffix);  // output: ****0004

Voir les résultats du test: https://jsfiddle.net/0quz9q9m/5/

Timothy Kanski
la source
vous devriez au moins faire `+ (insertString ||" ") +` au lieu de `+ insertString + , otherwise the third argument is not optional. This implementation also doesn't take care of startIndex <0` contrairement aux autres suggestions. Excellent exemple d'utilisation, cependant
YakovL
3

Il semble y avoir beaucoup de confusion qui n'a été abordée que dans les commentaires d'elclanrs et de raina77ow, alors permettez-moi de poster une réponse clarifiant.

Clarification

De " string.splice" on peut s'attendre à ce que, comme celui des tableaux:

  • accepte jusqu'à 3 arguments: position de départ, longueur et (facultativement) insertion (chaîne)
  • renvoie la partie découpée
  • modifie la chaîne d'origine

Le problème est que l'exigence 3d ne peut pas être remplie car les chaînes sont immuables (liées: 1 , 2 ), j'ai trouvé le commentaire le plus dédié ici :

En JavaScript, les chaînes sont des types de valeur primitifs et non des objets ( spécification ). En fait, de ES5, ils sont l' un des seuls 5 types de valeur à côté null, undefined, numberet boolean. Les chaînes sont attribuées par valeur et non par référence et sont transmises comme telles. Ainsi, les chaînes ne sont pas simplement immuables, elles sont une valeur . Changer la chaîne "hello"pour qu'elle soit, "world"c'est comme décider qu'à partir de maintenant le nombre 3 est le nombre 4 ... cela n'a aucun sens.

Donc, avec cela en compte, on peut s'attendre à ce que la string.splicechose " " soit seulement:

  • accepte jusqu'à 2 arguments: position de départ, longueur (l'insertion n'a aucun sens car la chaîne n'est pas modifiée)
  • renvoie la partie découpée

qui est ce que substrfait; Ou bien,

  • accepte jusqu'à 3 arguments: position de départ, longueur et (facultativement) insertion (chaîne)
  • renvoie la chaîne modifiée (sans la partie coupée et avec insertion)

qui fait l'objet de la section suivante.

Solutions

Si vous vous souciez de l'optimisation, vous devriez probablement utiliser l'implémentation de Mike:

String.prototype.splice = function(index, count, add) {
    if (index < 0) {
        index += this.length;
        if (index < 0)
            index = 0;
    }
    return this.slice(0, index) + (add || "") + this.slice(index + count);
}

Cependant, le traitement de l'indice hors limites peut varier. Selon vos besoins, vous voudrez peut-être:

    if (index < 0) {
        index += this.length;
        if (index < 0)
            index = 0;
    }
    if (index >= this.length) {
        index -= this.length;
        if (index >= this.length)
            index = this.length - 1;
    }

ou même

    index = index % this.length;
    if (index < 0)
        index = this.length + index;

Si vous ne vous souciez pas des performances, vous voudrez peut-être adapter la suggestion de Kumar qui est plus simple:

String.prototype.splice = function(index, count, add) {
    var chars = this.split('');
    chars.splice(index, count, add);
    return chars.join('');
}

Performance

La différence de performances augmente considérablement avec la longueur de la corde. jsperf montre que pour les chaînes d'une longueur de 10, la dernière solution (division et jointure) est deux fois plus lente que la première solution (en utilisant slice), pour les chaînes de 100 lettres, c'est x5 et pour les chaînes de 1000 lettres, c'est x50, dans Ops / sec c'est:

                      10 letters   100 letters   1000 letters
slice implementation    1.25 M       2.00 M         1.91 M
split implementation    0.63 M       0.22 M         0.04 M

notez que j'ai changé les 1er et 2ème arguments en passant de 10 lettres à 100 lettres (je suis toujours surpris que le test pour 100 lettres soit plus rapide que pour 10 lettres).

YakovL
la source
2

Utilisez simplement substr pour la chaîne

ex.

var str = "Hello world!";
var res = str.substr(1, str.length);

Résultat = bonjour le monde!

Dinesh Patil
la source
1

Ainsi, quelle que soit l'ajout de la méthode d'épissure à un prototype String ne peut pas fonctionner de manière transparente aux spécifications ...

Faisons une extension:

String.prototype.splice = function(...a){
    for(var r = '', p = 0, i = 1; i < a.length; i+=3)
        r+= this.slice(p, p=a[i-1]) + (a[i+1]||'') + this.slice(p+a[i], p=a[i+2]||this.length);
    return r;
}
  • Tous les 3 groupes d'arguments "insertion" dans le style d'épissure.
  • Spécial s'il y a plus d'un groupe de 3 arguments, la fin de chaque coupure sera le début du suivant.
    • «0123456789» .splice (4,1, «quatrième», 8,1, «huitième»); // retourne "0123fourth567eighth9"
  • Vous pouvez supprimer ou remettre à zéro le dernier argument de chaque groupe (traité comme "rien à insérer")
    • «0123456789». Épissure (-4,2); // retourne '0123459'
  • Vous pouvez tout supprimer sauf le 1er argument du dernier groupe (qui est traité comme "couper tout après la 1ère position d'argument")
    • '0123456789' .splice (0,2, nul, 3,1, nul, 5,2, '/', 8); // retourne «24/7»
  • si vous passez plusieurs, vous DEVEZ vérifier par vous-même le tri des positions de gauche à droite!
  • Et si vous ne voulez pas, vous DEVEZ NE PAS l'utiliser comme ceci:
    • '0123456789'.splice (4, -3,' quoi? '); // renvoie "0123 what? 123456789"
Fedor Tykmakov
la source
0

La méthode Réponse de Louis , en tant que Stringfonction prototype:

String.prototype.splice = function(index, count, add) {
  if (index < 0) {
    index = this.length + index;
    if (index < 0) {
      index = 0;
    }
  }
  return this.slice(0, index) + (add || "") + this.slice(index + count);
}

Exemple:

 > "Held!".splice(3,0,"lo Worl")
 < "Hello World!"
Mike Godin
la source
0

La méthode spliceSlice de Louis échoue lorsque la valeur ajoutée est 0 ou d'autres valeurs fausses, voici un correctif:

function spliceSlice(str, index, count, add) {
  if (index < 0) {
    index = str.length + index;
    if (index < 0) {
      index = 0;
    }
  }
  const hasAdd = typeof add !== 'undefined';
  return str.slice(0, index) + (hasAdd ? add : '') + str.slice(index + count);
}
Maryus Martsyalis
la source
0

J'ai résolu mon problème en utilisant ce code, c'est un peu un remplacement pour l'épissure manquante.

let str = "I need to remove a character from this";
let pos = str.indexOf("character")

if(pos>-1){
  let result = str.slice(0, pos-2) + str.slice(pos, str.length);
  console.log(result) //I need to remove character from this 
}

J'avais besoin de supprimer un caractère avant / après un certain mot, après avoir obtenu la position, la chaîne est divisée en deux, puis recomposée en supprimant de manière flexible les caractères en utilisant un décalage le long pos

Rayon restant
la source