Existe um método de emenda para strings?

87

O Javascript splicesó funciona com arrays. Existe um método semelhante para strings? Ou devo criar minha própria função personalizada?

Os métodos substr(), e substring()retornarão apenas a string extraída e não modificarão a string original. O que eu quero fazer é remover alguma parte da minha corda e aplicar a mudança na corda original. Além disso, o método replace()não funcionará no meu caso porque desejo remover partes começando de um índice e terminando em algum outro índice, exatamente como posso fazer com o splice()método. Tentei converter minha string em um array, mas este não é um método legal.

ProllyGeek
fonte
str.splitpode ser a função que você está procurando: google.com/#q=javascript+string+split
Anderson Green
1
O que há de errado str = str.slice()?
elclanrs
1
Parece um problema XY, o que você está tentando fazer exatamente? Strings não são passadas por referência, ao contrário de arrays e objetos, portanto, você não altera strings, cria novas ou reatribui a nova à antiga.
elclanrs
1
possível duplicata de Set String via função String.prototype sem retorno
raina77ow
6
return string.slice(0, startToSplice) + string.slice(endToSplice);, não?
raina77ow

Respostas:

88

É mais rápido cortar a string duas vezes, assim:

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

do que usar uma divisão seguida por uma junção (método de Kumar Harsh), como este:

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

Aqui está um jsperf que compara os dois e alguns outros métodos. (jsperf está fora do ar há alguns meses. Sugira alternativas nos comentários.)

Embora o código acima implemente funções que reproduzem a funcionalidade geral de splice, otimizar o código para o caso apresentado pelo autor da pergunta (ou seja, não adicionar nada à string modificada) não altera o desempenho relativo dos vários métodos.

Louis
fonte
3
Você pode adicionar isso globalmente com: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Apenas tenha em mente que não funciona exatamente da mesma forma que o método de emenda de array porque as strings são imutáveis ​​(você não pode modificá-las depois de criadas). Portanto, o uso seria assim:var s="ss"; s = s.splice(0,1,"t");
William Neely
@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};seria o padrão para manipulação de strings, pois você disse que é imutável.
Sr. Polywhirl
spliceSlice e spliceSplit não são funcionalmente iguais devido a Array.prototype.splice aceitar índices negativos: jsfiddle.net/sykteho6/5 .
Martijn
1
@Mzialla Obrigado, adicionei o código para cuidar disso.
Louis
Criar variáveis ​​temporárias e introduzir locais para erros individuais, sem mencionar o código que leva mais tempo para ser processado por humanos em vez de dividir (""). Splice (...). Join ("") é uma compensação que merece consideração. O problema da velocidade só é um problema se for um problema.
Ben Fletcher
15

Editar

Obviamente, essa não é a melhor maneira de "unir" uma string, dei isso como um exemplo de como seria a implementação, o que é falho e muito evidente em split (), splice () e join (). Para uma implementação muito melhor, consulte o método de Louis .


Não, não existe tal coisa como um String.splice, mas você pode tentar isto:

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

Sei que não há splicefunção como em Arrays, então você deve converter a string em um array. Má sorte...

Kumarharsh
fonte
no meu caso, estou trabalhando em uma string dinâmica, então preciso especificar índices e não o valor do caractere.
ProllyGeek
Sim, infelizmente está correto. Mas você pode obter o índice de um caractere usando String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh
3
Em vez de usar str.split, você pode usar a sintaxe de propagação ES6 da seguinte forma:[...str]
robbie
5

Aqui está um pequeno Curry agradável que oferece melhor legibilidade (IMHO):

A assinatura da segunda função é idêntica ao 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');

Eu sei que já existe uma resposta aceita, mas espero que isso seja útil.

Cody
fonte
1
Np. Você pode até abstrair isso para permitir, digamos, um 'method'parâmetro opcional para que você possa passar um Array.prototype[method]e tratar as strings completamente como matrizes. Além disso, com este sozinho, você poderia abstrair o processo real para outra função - e se não há nenhuma corda, retornar uma função que irá tomar a corda e reverter o caril: mutate()(1, 1, '1')('101'); Você poderia até mesmo duckType os argumentos para livrar o curry da invocação vazia - até mesmo encapsular o próprio método. Se você precisar disso, pode dar uma olhada no Padrão de Comando . Apenas cuspindo aqui.
Cody de
3

Eu gostaria de oferecer uma alternativa mais simples para os métodos Kumar / Cody e Louis. Em todos os testes que executei, ele tem um desempenho tão rápido quanto o método Louis (consulte os testes de violino para obter os benchmarks).

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

Você pode usá-lo assim:

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

Consulte os resultados do teste: https://jsfiddle.net/0quz9q9m/5/

Timothy Kanski
fonte
você deve pelo menos fazer `+ (insertString ||" ") +` ao invés de `+ insertString + startIndex , otherwise the third argument is not optional. This implementation also doesn't take care of <0` ao contrário de outras sugestões. Grande exemplo de uso, no entanto
YakovL
3

Parece haver muita confusão que foi abordada apenas nos comentários de elclanrs e raina77ow, então deixe-me postar uma resposta esclarecedora.

Esclarecimento

De " string.splice" pode-se esperar que, como aquele para arrays:

  • aceita até 3 argumentos: posição inicial, comprimento e (opcionalmente) inserção (string)
  • retorna a parte cortada
  • modifica a string original

O problema é que o requisito 3D não pode ser atendido porque as strings são imutáveis ​​(relacionadas: 1 , 2 ), encontrei o comentário mais dedicado aqui :

Em JavaScript, as strings são tipos de valores primitivos e não objetos ( especificação ). Na verdade, a partir de ES5, eles são um dos apenas 5 tipos de valor ao lado null, undefined, numbere boolean. As strings são atribuídas por valor e não por referência e são passadas como tal. Portanto, as strings não são apenas imutáveis, elas são um valor . Mudar a string "hello"para ser "world"é como decidir que a partir de agora o número 3 é o número 4 ... não faz sentido.

Portanto, com isso em consideração, pode-se esperar que a string.splicecoisa " " apenas:

  • aceita até 2 argumentos: posição inicial, comprimento (a inserção não faz sentido, pois a string não é alterada)
  • retorna a parte cortada

que é o que substrfaz; ou alternativamente,

  • aceita até 3 argumentos: posição inicial, comprimento e (opcionalmente) inserção (string)
  • retorna a string modificada (sem a parte cortada e com inserção)

que é o assunto da próxima seção.

Soluções

Se você se preocupa com a otimização, provavelmente deve usar a implementação 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);
}

No entanto, tratar o índice fora dos limites pode variar. Dependendo de suas necessidades, você pode desejar:

    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 mesmo

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

Se você não se preocupa com o desempenho, pode querer adaptar a sugestão de Kumar, que é mais direta:

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

atuação

A diferença de desempenho aumenta drasticamente com o comprimento da corda. jsperf mostra que, para strings com o comprimento de 10, a última solução (divisão e junção) é duas vezes mais lenta do que a solução anterior (usando o slice), para strings de 100 letras é x5 e para strings de 1000 letras é x50, em Ops / segundo é:

                      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

note que eu mudei o primeiro e o segundo argumento ao passar de 10 letras para 100 letras (ainda estou surpreso que o teste para 100 letras é mais rápido do que para 10 letras).

YakovL
fonte
2

Basta usar substr para string

ex.

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

Resultado = mundo ello!

Dinesh Patil
fonte
1

Portanto, qualquer método de emenda de adição a um protótipo de String não pode funcionar de forma transparente para as especificações ...

Vamos estender isso:

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 args "inserindo" no estilo splice.
  • Especial se houver mais de um grupo de 3 argumentos, o final de cada corte será o início do próximo.
    • '0123456789'.splice (4,1,' quarto ', 8,1,' oitavo '); // retorna '0123fourth567eighth9'
  • Você pode descartar ou zerar o último argumento em cada grupo (que é tratado como "nada a ser inserido")
    • '0123456789'.splice (-4,2); // retorna '0123459'
  • Você pode descartar todos, exceto o primeiro argumento no último grupo (que é tratado como "cortar todos após a primeira posição do argumento")
    • '0123456789'.splice (0,2, nulo, 3,1, nulo, 5,2,' / ', 8); // retorna '24 / 7 '
  • se você passar por vários, você DEVE verificar o tipo de posição da esquerda para a direita por si mesmo!
  • E se você não quiser, NÃO DEVE usar assim:
    • '0123456789'.splice (4, -3,' o quê? '); // retorna "0123what? 123456789"
Fedor Tykmakov
fonte
0

A resposta de Louis do método , como Stringfunção de protótipo:

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

Exemplo:

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

O método spliceSlice de Louis falha quando o valor adicionado é 0 ou outros valores falsos, aqui está uma correção:

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

Resolvi meu problema usando este código, é um substituto para a emenda que falta.

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 
}

Eu precisava remover um caractere antes / depois de uma determinada palavra, depois de obter a posição, a string é dividida em duas e então recomposta removendo caracteres de forma flexível usando um deslocamento ao longo pos

Ray Remnant
fonte