¿Existe un método de empalme para cuerdas?

87

El Javascript splicesolo funciona con matrices. ¿Existe un método similar para las cadenas? ¿O debería crear mi propia función personalizada?

Los métodos substr(), y substring()solo devolverán la cadena extraída y no modificarán la cadena original. Lo que quiero hacer es eliminar alguna parte de mi cadena y aplicar el cambio a la cadena original. Además, el método replace()no funcionará en mi caso porque quiero eliminar partes comenzando desde un índice y terminando en algún otro índice, exactamente como lo que puedo hacer con el splice()método. Intenté convertir mi cadena en una matriz, pero este no es un método ordenado.

ProllyGeek
fuente
str.splitpodría ser la función que está buscando: google.com/#q=javascript+string+split
Anderson Green
1
¿Qué pasa con str = str.slice()?
elclanrs
1
Parece un problema XY, ¿qué estás intentando hacer exactamente? Las cadenas no se pasan por referencia, a diferencia de las matrices y los objetos, por lo que no mute cadenas, cree nuevas o reasigne la nueva a la anterior.
elclanrs
6
return string.slice(0, startToSplice) + string.slice(endToSplice);, ¿No?
raina77ow

Respuestas:

88

Es más rápido cortar la cuerda dos veces, así:

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 usar una división seguida de una combinación (método de Kumar Harsh), así:

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

Aquí hay un jsperf que compara los dos y un par de otros métodos. (jsperf ha estado inactivo durante algunos meses. Sugiera alternativas en los comentarios).

Aunque el código anterior implementa funciones que reproducen la funcionalidad general de splice, optimizar el código para el caso presentado por el autor de la pregunta (es decir, no agregar nada a la cadena modificada) no cambia el rendimiento relativo de los diversos métodos.

Luis
fuente
3
Puede agregar esto globalmente con: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Solo tenga en cuenta que no funciona exactamente igual que el método de empalme de matriz porque las cadenas son inmutables (no puede modificarlas una vez creadas). Entonces el uso sería como:var s="ss"; s = s.splice(0,1,"t");
William Neely
@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};sería estándar para la manipulación de cadenas, ya que ha dicho que es inmutable.
Mr. Polywhirl
spliceSlice y spliceSplit no son funcionalmente iguales debido a que Array.prototype.splice acepta índices negativos: jsfiddle.net/sykteho6/5 .
Martijn
1
@Mzialla Gracias, agregué código para solucionarlo.
Louis
Crear variables temporales e introducir lugares para errores uno por uno, sin mencionar el código que los humanos tardan más en procesar en lugar de dividir (""). Splice (...). Join ("") es una compensación que merece consideración. El problema de la velocidad solo es un problema si es un problema.
Ben Fletcher
15

Editar

Por supuesto, esta no es la mejor manera de "empalmar" una cadena, lo había dado como un ejemplo de cómo sería la implementación, que es defectuosa y muy evidente en split (), splice () y join (). Para una implementación mucho mejor, consulte el método de Louis .


No, no existe tal cosa como a String.splice, pero puedes probar esto:

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

Me doy cuenta de que no hay splicefunción como en las matrices, por lo que debe convertir la cadena en una matriz. Mala suerte...

Kumarharsh
fuente
en mi caso, estoy trabajando en una cadena dinámica, así que necesito especificar índices y no valores de caracteres.
ProllyGeek
Sí, lamentablemente eso es correcto. Pero puede obtener el índice de un carácter utilizando String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh
3
En lugar de usar str.split, puede usar la sintaxis de propagación de ES6 así:[...str]
robbie
5

Aquí hay un curry pequeño y agradable que brinda una mejor legibilidad (en mi humilde opinión):

La firma de la segunda función es idéntica al Array.prototype.splicemétodo.

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

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

Sé que ya hay una respuesta aceptada, pero espero que sea útil.

Cody
fuente
1
Notario público. Incluso puede abstraer esto para permitir, digamos, un 'method'parámetro opcional para que pueda pasar Array.prototype[method]y tratar cadenas completamente como matrices. Además, con solo ésta, se podía abstraer el proceso real de otra función - y si no hay ninguna cadena, regresar una función que tendrá la cadena y revertir el curry: mutate()(1, 1, '1')('101'); Incluso podría duckType los argumentos para eliminar el curry de la invocación vacía, incluso encapsular un método en sí. Sin embargo, si necesita estas cosas, es posible que desee consultar el Patrón de comando . Solo escupir aquí.
Cody
3

Me gustaría ofrecer una alternativa más sencilla a los métodos de Kumar / Cody y Louis. En todas las pruebas que ejecuté, funciona tan rápido como el método Louis (consulte las pruebas de violín para ver los puntos de referencia).

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

Puedes usarlo así:

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

Consulte los resultados de la prueba: https://jsfiddle.net/0quz9q9m/5/

Timothy Kanski
fuente
debería al menos hacer `+ (insertString ||" ") +` en lugar de `+ insertString + , otherwise the third argument is not optional. This implementation also doesn't take care of startIndex <0` a diferencia de otras sugerencias. Sin embargo, es un gran ejemplo de uso
YakovL
3

Parece haber mucha confusión que solo se abordó en los comentarios de elclanrs y raina77ow, así que permítanme publicar una respuesta aclaratoria.

Aclaración

De " string.splice" uno puede esperar que, como el de las matrices:

  • acepta hasta 3 argumentos: posición inicial, longitud y (opcionalmente) inserción (cadena)
  • devuelve la parte cortada
  • modifica la cadena original

El problema es que el requisito de 3d no se puede cumplir porque las cadenas son inmutables (relacionado: 1 , 2 ), he encontrado el comentario más dedicado aquí :

En JavaScript, las cadenas son tipos de valores primitivos y no objetos ( especificación ). De hecho, a partir de ES5, que son uno de los únicos 5 tipos de valor junto con null, undefined, numbery boolean. Las cadenas se asignan por valor y no por referencia y se pasan como tales. Por lo tanto, las cadenas no solo son inmutables, son un valor . Cambiar la cadena "hello"a ser "world"es como decidir que a partir de ahora el número 3 es el número 4 ... no tiene sentido.

Entonces, con eso en cuenta, uno puede esperar que la string.splicecosa " " solo:

  • acepta hasta 2 argumentos: posición inicial, longitud (la inserción no tiene sentido ya que la cadena no se cambia)
  • devuelve la parte cortada

que es lo que substrhace; o alternativamente,

  • acepta hasta 3 argumentos: posición inicial, longitud y (opcionalmente) inserción (cadena)
  • devuelve la cadena modificada (sin la parte cortada y con inserción)

que es el tema de la siguiente sección.

Soluciones

Si le interesa optimizar, probablemente debería usar la implementación 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);
}

Sin embargo, el tratamiento del índice de fuera de límites puede variar. Según sus necesidades, es posible que desee:

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

o incluso

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

Si no le importa el rendimiento, es posible que desee adaptar la sugerencia de Kumar, que es más sencilla:

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

Actuación

La diferencia de rendimiento aumenta drásticamente con la longitud de la cuerda. jsperf muestra que para cadenas con una longitud de 10, la última solución (dividir y unir) es dos veces más lenta que la solución anterior (usando slice), para cadenas de 100 letras es x5 y para cadenas de 1000 letras es x50, en Ops / sec es:

                      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

tenga en cuenta que cambié los argumentos 1er y 2d al pasar de 10 letras a 100 letras (aún me sorprende que la prueba de 100 letras sea más rápida que la de 10 letras).

YakovL
fuente
2

Simplemente use substr para cadena

ex.

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

Resultado = ello mundo!

Dinesh Patil
fuente
1

Entonces, cualquier método de empalme agregado a un prototipo de String no puede funcionar transparente según las especificaciones ...

Hagamos que alguien lo extienda:

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;
}
  • Cada grupo de 3 argumentos "inserta" en estilo empalme.
  • Especial si hay más de un grupo de 3 argumentos, el final de cada corte será el comienzo del siguiente.
    • '0123456789'.splice (4,1,' cuarto ', 8,1,' octavo '); // devuelve '0123fourth567eighth9'
  • Puede eliminar o poner a cero el último argumento de cada grupo (que se trata como "nada para insertar")
    • '0123456789'. Empalme (-4,2); // devuelve '0123459'
  • Puede eliminar todo excepto el primer argumento en el último grupo (el que se trata como "cortar todo después de la posición del primer argumento")
    • '0123456789'.splice (0,2, nulo, 3,1, nulo, 5,2,' / ', 8); // devuelve '24 / 7 '
  • si aprueba varias, DEBE comprobar el tipo de posiciones en orden de izquierda a derecha por sí mismo.
  • Y si no lo desea, NO DEBE usarlo así:
    • '0123456789'.splice (4, -3,' ¿qué? '); // devuelve "0123 what? 123456789"
Fedor Tykmakov
fuente
0

El método respuesta de Louis , como Stringfunción prototipo:

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

Ejemplo:

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

El método spliceSlice de Louis falla cuando el valor agregado es 0 u otros valores falsos, aquí hay una solución:

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
fuente
0

Resolví mi problema usando este código, es un reemplazo para el empalme faltante.

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 
}

Necesitaba eliminar un carácter antes / después de una determinada palabra, después de obtener la posición, la cadena se divide en dos y luego se recompone eliminando caracteres de manera flexible con un desplazamiento a lo largo pos

Ray Remnant
fuente