Como você inverte uma string no JavaScript?


435

Como você reverte uma string no local (ou no local) no JavaScript quando é passada para uma função com uma instrução de retorno, sem usar funções internas ( .reverse(), .charAt()etc.)?


então, você não tem permissão para usar .charAt () para obter os caracteres da string?
Irwin

155
Você não pode. As strings JavaScript são imutáveis, o que significa que a memória alocada para cada um não pode ser gravada, impossibilitando as verdadeiras reversões "no local".
Crescent Fresh

2
Re: comentário de crescentfresh consulte stackoverflow.com/questions/51185/…
baudtack 6/06

1
@crescentfresh você deve postar isso como uma nova resposta.
baudtack

Respostas:


736

Contanto que você esteja lidando com caracteres ASCII simples e esteja feliz em usar funções internas, isso funcionará:

function reverse(s){
    return s.split("").reverse().join("");
}

Se você precisar de uma solução que suporte UTF-16 ou outros caracteres de vários bytes, saiba que esta função fornecerá cadeias unicode inválidas ou cadeias válidas que parecerão engraçadas. Você pode considerar esta resposta .

[... s] reconhece Unicode, uma pequena edição fornece: -

function reverse(s){
    return [...s].reverse().join("");
}

44
Isso é interrompido para cadeias UTF-16 que contêm pares substitutos, ou seja, caracteres fora do plano multilíngue básico. Também fornecerá resultados engraçados para cadeias que contêm caracteres combinados, por exemplo, uma diérese pode aparecer no seguinte caractere. O primeiro problema levará a seqüências unicode inválidas, o segundo a sequências válidas que parecem engraçadas.
Martin Probst

2
@Richeve Bebedor "Tudo sem usar as funções internas? .Reverse ()" Esta não seria uma solução aceita, pois não se encaixa nos limites da pergunta, apesar de ser uma solução viável para reverter uma string em JS.
David Starkey

1
@ DavidStarkey: Sim, olhando para trás quase quatro anos depois, é difícil ver como eu errei tanto o ponto da questão. Parece que eu deveria ter esperado dois minutos e votado acima no comentário de crescentfresh na postagem original!
Belacqua

14
@MartinProbst Minha resposta fornece uma solução compatível com Unicode para o problema que lida com pares substitutos e combinando marcas corretamente: stackoverflow.com/a/16776380/96656
Mathias Bynens

1
Para UTF-16 return [...s].reverse().join("");pode funcionar.
user4642212

411

A seguinte técnica (ou semelhante) é comumente usada para reverter uma string em JavaScript:

// Don’t use this!
var naiveReverse = function(string) {
    return string.split('').reverse().join('');
}

De fato, todas as respostas postadas até agora são uma variação desse padrão. No entanto, existem alguns problemas com esta solução. Por exemplo:

naiveReverse('foo 𝌆 bar');
// → 'rab �� oof'
// Where did the `𝌆` symbol go? Whoops!

Se você está se perguntando por que isso acontece, leia a codificação interna de caracteres do JavaScript . (TL; DR: 𝌆é um símbolo astral e o JavaScript o expõe como duas unidades de código separadas.)

Mas tem mais:

// To see which symbols are being used here, check:
// http://mothereff.in/js-escapes#1ma%C3%B1ana%20man%CC%83ana
naiveReverse('mañana mañana');
// → 'anãnam anañam'
// Wait, so now the tilde is applied to the `a` instead of the `n`? WAT.

Uma boa sequência para testar implementações reversas é a seguinte :

'foo 𝌆 bar mañana mañana'

Por quê? Porque contém um símbolo astral (𝌆 ) (que é representado por pares substitutos em JavaScript ) e uma marca combinada ( a última mañanana verdade consiste em dois símbolos: U + 006E LETRA PEQUENA LATINA N e U + 0303 COMBINING TILDE).

A ordem na qual os pares substitutos aparecem não pode ser revertida; caso contrário, o símbolo astral não aparecerá mais na sequência 'invertida'. É por isso que você viu essas ��marcas na saída do exemplo anterior.

As marcas combinadas sempre são aplicadas ao símbolo anterior; portanto, você deve tratar o símbolo principal (U + 006E LETRA PEQUENA N) como a marca combinada (U + 0303 COMBINING TILDE) como um todo. Inverter a ordem fará com que a marca combinada seja emparelhada com outro símbolo na sequência. É por isso que a saída de exemplo teve em vez de ñ.

Felizmente, isso explica por que todas as respostas postadas até agora estão erradas .


Para responder à sua pergunta inicial - como reverter [adequadamente] uma string em JavaScript -, escrevi uma pequena biblioteca JavaScript capaz de reverter seqüências compatíveis com Unicode. Não possui nenhum dos problemas que acabei de mencionar. A biblioteca é chamada Esrever ; seu código está no GitHub e funciona em praticamente qualquer ambiente JavaScript. Ele vem com um utilitário de shell / binário, para que você possa reverter facilmente as strings do seu terminal, se desejar.

var input = 'foo 𝌆 bar mañana mañana';
esrever.reverse(input);
// → 'anañam anañam rab 𝌆 oof'

Quanto à parte "no local", consulte as outras respostas.


65
Você deve incluir a parte principal do código da Esrever em sua resposta.
R0estir0bbe 31/07/2014

1
@Meglio Com essa abordagem específica, sim.
Mathias Bynens

8
O problema, é claro, é que "reverter uma string" parece inequívoco, mas não está diante dos problemas mencionados aqui. A reversão de uma string está retornando a string que, quando impressa, exibia os clusters de grafema na string na ordem inversa? Por um lado, isso parece provável. Por outro lado, por que você iria querer fazer isso? Essa definição depende da impressão e a impressão de uma sequência invertida raramente é útil. Como parte de um algoritmo, seus requisitos podem ser completamente diferentes.
287 Martijn

19
Enquanto isto faz um grande trabalho de explicar o problema, o real resposta é em um outro castelo . Como o @ r0estir0bbe disse há mais de um ano, o código relevante deve estar na resposta, não apenas no link.
TJ Crowder

4
"Felizmente, isso explica por que todas as respostas postadas até agora estão erradas" - Essa afirmação é imo demais. Muitos casos de uso não requerem suporte a UTF-16 (exemplo simples; trabalhando com URLs e componentes / parâmetros de URL). Uma solução não está "errada" simplesmente porque não lida com um cenário não obrigatório. Notavelmente, a resposta mais votada declara explicitamente que só funciona com caracteres ASCII e, portanto, definitivamente não está nem um pouco errada.
Aroth

92
String.prototype.reverse_string=function() {return this.split("").reverse().join("");}

ou

String.prototype.reverse_string = function() {
    var s = "";
    var i = this.length;
    while (i>0) {
        s += this.substring(i-1,i);
        i--;
    }
    return s;
}

Eu definitivamente concordo com o protótipo String.
Jeff Meatball Yang

3
a concatenação de strings é cara. Melhor construir uma matriz e associá-la ou usar concat ().
Bjorn

2
# 1 é melhor, # 2 poderia ser terrivelmente lento
adamJLev

9
No entanto, nenhuma solução funciona quando caracteres compostos Unicode estão presentes.
Eric Grange

2
@JuanMendes Deixei esse comentário em 2009, as coisas mudaram nos últimos 4 anos. : P
Bjorn

63

Análise detalhada e dez maneiras diferentes de reverter uma string e seus detalhes de desempenho.

http://eddmann.com/posts/ten-ways-to-reverse-a-string-in-javascript/

Desempenho dessas implementações:

Implementações de melhor desempenho por navegador

  • Chrome 15 - Implementações 1 e 6
  • Firefox 7 - Implementação 6
  • IE 9 - Implementação 4
  • Opera 12 - Implementação 9

Aqui estão essas implementações:

Implementação 1:

function reverse(s) {
  var o = '';
  for (var i = s.length - 1; i >= 0; i--)
    o += s[i];
  return o;
}

Implementação 2:

function reverse(s) {
  var o = [];
  for (var i = s.length - 1, j = 0; i >= 0; i--, j++)
    o[j] = s[i];
  return o.join('');
}

Implementação 3:

function reverse(s) {
  var o = [];
  for (var i = 0, len = s.length; i <= len; i++)
    o.push(s.charAt(len - i));
  return o.join('');
}

Implementação 4:

function reverse(s) {
  return s.split('').reverse().join('');
}

Implementação 5:

function reverse(s) {
  var i = s.length,
      o = '';
  while (i > 0) {
    o += s.substring(i - 1, i);
    i--;
  }
  return o;
}

Implementação 6:

function reverse(s) {
  for (var i = s.length - 1, o = ''; i >= 0; o += s[i--]) { }
  return o;
}

Implementação 7:

function reverse(s) {
  return (s === '') ? '' : reverse(s.substr(1)) + s.charAt(0);
}

Implementação 8:

function reverse(s) {
  function rev(s, len, o) {
    return (len === 0) ? o : rev(s, --len, (o += s[len]));
  };
  return rev(s, s.length, '');
}

Implementação 9:

function reverse(s) {
  s = s.split('');
  var len = s.length,
      halfIndex = Math.floor(len / 2) - 1,
      tmp;


     for (var i = 0; i <= halfIndex; i++) {
        tmp = s[len - i - 1];
        s[len - i - 1] = s[i];
        s[i] = tmp;
      }
      return s.join('');
    }

Implementação 10

function reverse(s) {
  if (s.length < 2)
    return s;
  var halfIndex = Math.ceil(s.length / 2);
  return reverse(s.substr(halfIndex)) +
         reverse(s.substr(0, halfIndex));
}

53

Todo o "inverter uma seqüência de caracteres no lugar" é uma pergunta de entrevista antiquada programadores C, e as pessoas que foram entrevistadas por eles (por vingança, talvez?), Perguntarão. Infelizmente, é a parte "No Local" que não funciona mais porque as strings em praticamente qualquer linguagem gerenciada (JS, C # etc.) usam sequências imutáveis, derrotando assim toda a idéia de mover uma sequência sem alocar nova memória.

Embora as soluções acima de fato invertam uma string, elas não o fazem sem alocar mais memória e, portanto, não atendem às condições. Você precisa ter acesso direto à string conforme alocado e poder manipular seu local de memória original para poder revertê-la no lugar.

Pessoalmente, eu realmente odeio esse tipo de perguntas para entrevistas, mas, infelizmente, tenho certeza de que continuaremos vendo-as nos próximos anos.


7
Pelo menos, posso dizer que, há algum tempo, um entrevistador ficou bastante impressionado quando ele me perguntou como reverter uma string "no local" em JS e expliquei por que é impossível, já que as strings em JS são imutáveis. Não sei se essa era a resposta que ele esperava ou se eu o ensinei um pouco. De qualquer maneira que funcionou bem;)
Chev

1
Talvez ele queira dizer "gerenciado" por um coletor de lixo, pelo menos é o que geralmente significa "linguagem gerenciada" ou a presença de uma máquina virtual / ambiente de tempo de execução virtual? @torazaburo
AntonB

39

Primeiro, use Array.from()para transformar uma string em uma matriz, depois Array.prototype.reverse()inverter a matriz e depois Array.prototype.join()transformá-la novamente em uma string.

const reverse = str => Array.from(str).reverse().join('');

Tem sobrecarga, mas esta é uma solução elegante! Não há reescrita da reverselógica pré-existente .
Gershom

2
@felixfbecker Não, string.split('')não funciona. Veja esta resposta para mais explicações.
Michał Perłakowski

5
Essa deve ser a resposta aceita, pois também funciona com unicode. Por exemplo, do exemplo acima:Array.from('foo 𝌆 bar mañana mañana').reverse().join('') == 'anãnam anañam rab 𝌆 oof'
Julian TF

3
@JulianTF Não exatamente, um til ainda é aplicado a 'a' em vez de 'n'.
Roman Boiko

2
@RomanBoiko True, mas você pode normalizar a string primeiro. Array.from('foo 𝌆 bar mañana mañana'.normalize('NFC')).reverse().join('')se tornará"anañam anañam rab 𝌆 oof"
Sr. Lister

26

No ECMAScript 6, você pode reverter uma string ainda mais rapidamente sem usar o .split('')método split, com o operador spread assim:

var str = [...'racecar'].reverse().join('');

1
O ES6 também permite que você use dois backticks `` em vez de('')

não há nenhuma razão para usar dois acentos graves neste caso
Vic

1
A menos que você seja um golfista de código, evite isso. Escrever string.split('')é mais claro para a maioria das pessoas do que [...string].
AnnanFay

1
O @AnnanFay .split('')tem o problema de caracteres dos planos suplementares (pares substitutos no UTF-16), porque ele é dividido pela unidade de código UTF-16 em vez do ponto do código . O operador de spread e Array.from()(minha preferência) não.
Inkling

@ Inkling Eu não sabia que era um problema. Obrigado por apontar isso. Eu ainda ficaria tentado a escrever uma função de utilidade para maior clareza.
AnnanFay 16/02

19

Parece que estou 3 anos atrasado para a festa ...

Infelizmente você não pode, como foi indicado. Consulte As strings do JavaScript são imutáveis? Preciso de um "construtor de strings" em JavaScript?

A próxima melhor coisa que você pode fazer é criar uma "view" ou "wrapper", que pega uma string e reimplementa quaisquer partes da API de string que você está usando, mas finge que a string está invertida. Por exemplo:

var identity = function(x){return x};

function LazyString(s) {
    this.original = s;

    this.length = s.length;
    this.start = 0; this.stop = this.length; this.dir = 1; // "virtual" slicing
    // (dir=-1 if reversed)

    this._caseTransform = identity;
}

// syntactic sugar to create new object:
function S(s) {
    return new LazyString(s);
}

//We now implement a `"...".reversed` which toggles a flag which will change our math:

(function(){ // begin anonymous scope
    var x = LazyString.prototype;

    // Addition to the String API
    x.reversed = function() {
        var s = new LazyString(this.original);

        s.start = this.stop - this.dir;
        s.stop = this.start - this.dir;
        s.dir = -1*this.dir;
        s.length = this.length;

        s._caseTransform = this._caseTransform;
        return s;
    }

//We also override string coercion for some extra versatility (not really necessary):

    // OVERRIDE STRING COERCION
    //   - for string concatenation e.g. "abc"+reversed("abc")
    x.toString = function() {
        if (typeof this._realized == 'undefined') {  // cached, to avoid recalculation
            this._realized = this.dir==1 ?
                this.original.slice(this.start,this.stop) : 
                this.original.slice(this.stop+1,this.start+1).split("").reverse().join("");

            this._realized = this._caseTransform.call(this._realized, this._realized);
        }
        return this._realized;
    }

//Now we reimplement the String API by doing some math:

    // String API:

    // Do some math to figure out which character we really want

    x.charAt = function(i) {
        return this.slice(i, i+1).toString();
    }
    x.charCodeAt = function(i) {
        return this.slice(i, i+1).toString().charCodeAt(0);
    }

// Slicing functions:

    x.slice = function(start,stop) {
        // lazy chaining version of https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice

        if (stop===undefined)
            stop = this.length;

        var relativeStart = start<0 ? this.length+start : start;
        var relativeStop = stop<0 ? this.length+stop : stop;

        if (relativeStart >= this.length)
            relativeStart = this.length;
        if (relativeStart < 0)
            relativeStart = 0;

        if (relativeStop > this.length)
            relativeStop = this.length;
        if (relativeStop < 0)
            relativeStop = 0;

        if (relativeStop < relativeStart)
            relativeStop = relativeStart;

        var s = new LazyString(this.original);
        s.length = relativeStop - relativeStart;
        s.start = this.start + this.dir*relativeStart;
        s.stop = s.start + this.dir*s.length;
        s.dir = this.dir;

        //console.log([this.start,this.stop,this.dir,this.length], [s.start,s.stop,s.dir,s.length])

        s._caseTransform = this._caseTransform;
        return s;
    }
    x.substring = function() {
        // ...
    }
    x.substr = function() {
        // ...
    }

//Miscellaneous functions:

    // Iterative search

    x.indexOf = function(value) {
        for(var i=0; i<this.length; i++)
            if (value==this.charAt(i))
                return i;
        return -1;
    }
    x.lastIndexOf = function() {
        for(var i=this.length-1; i>=0; i--)
            if (value==this.charAt(i))
                return i;
        return -1;
    }

    // The following functions are too complicated to reimplement easily.
    // Instead just realize the slice and do it the usual non-in-place way.

    x.match = function() {
        var s = this.toString();
        return s.apply(s, arguments);
    }
    x.replace = function() {
        var s = this.toString();
        return s.apply(s, arguments);
    }
    x.search = function() {
        var s = this.toString();
        return s.apply(s, arguments);
    }
    x.split = function() {
        var s = this.toString();
        return s.apply(s, arguments);
    }

// Case transforms:

    x.toLowerCase = function() {
        var s = new LazyString(this.original);
        s._caseTransform = ''.toLowerCase;

        s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;

        return s;
    }
    x.toUpperCase = function() {
        var s = new LazyString(this.original);
        s._caseTransform = ''.toUpperCase;

        s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;

        return s;
    }

})() // end anonymous scope

Demo:

> r = S('abcABC')
LazyString
  original: "abcABC"
  __proto__: LazyString

> r.charAt(1);       // doesn't reverse string!!! (good if very long)
"B"

> r.toLowerCase()    // must reverse string, so does so
"cbacba"

> r.toUpperCase()    // string already reversed: no extra work
"CBACBA"

> r + '-demo-' + r   // natural coercion, string already reversed: no extra work
"CBAcba-demo-CBAcba"

O kicker - o seguinte é feito no local por pura matemática, visitando cada personagem apenas uma vez e somente se necessário:

> 'demo: ' + S('0123456789abcdef').slice(3).reversed().slice(1,-1).toUpperCase()
"demo: EDCBA987654"

> S('0123456789ABCDEF').slice(3).reversed().slice(1,-1).toLowerCase().charAt(3)
"b"

Isso gera uma economia significativa se aplicada a uma cadeia muito grande, se você estiver usando apenas uma fatia relativamente pequena.

Se vale a pena (reverter como uma cópia, como na maioria das linguagens de programação) depende muito do seu caso de uso e da eficiência com que você reimplementa a API de cadeia de caracteres. Por exemplo, se tudo o que você deseja é manipular o índice de cadeias de caracteres ou usar slices ou s pequenos substr, isso economizará espaço e tempo. No entanto, se você planeja imprimir grandes fatias ou substratos invertidos, a economia pode ser pequena, ainda pior do que ter feito uma cópia completa. Sua string "invertida" também não terá o tipostring , embora você possa fingir isso com a criação de protótipos.

A implementação de demonstração acima cria um novo objeto do tipo ReversedString. É prototipado e, portanto, bastante eficiente, com trabalho quase mínimo e sobrecarga de espaço mínima (as definições de protótipo são compartilhadas). É uma implementação lenta que envolve fatiamento diferido. Sempre que você executa uma função como .sliceou .reversed, ela executa matemática de índice. Finalmente, quando você extrai dados (chamando implicitamente .toString()ou.charCodeAt(...) ou algo assim), aplicará os de uma forma "inteligente", tocando o mínimo de dados possível.

Nota: a API da string acima é um exemplo e pode não ser implementada perfeitamente. Você também pode usar apenas 1-2 funções necessárias.


13

Existem várias maneiras de reverter uma string em JavaScript. Estou anotando três maneiras que prefiro.

Abordagem 1: Usando a função reversa:

function reverse(str) {
  return str.split('').reverse().join('');
}

Abordagem 2: Loop através dos personagens:

function reverse(str) {
  let reversed = '';

  for (let character of str) {
    reversed = character + reversed;
  }

  return reversed;
}

Abordagem 3: Usando a função de redução:

function reverse(str) {
  return str.split('').reduce((rev, char) => char + rev, '');
}

Eu espero que isso ajude :)


10

Durante uma entrevista, me pediram para reverter uma string sem usar variáveis ​​ou métodos nativos. Esta é minha implementação favorita:

function reverseString(str) {
    return str === '' ? '' : reverseString(str.slice(1)) + str[0];
}

Curto, simples, mas lento como o inferno;)
Tom

13
Zero métodos nativos? Que tal slice? : - /
leaf

1
Uso interessante de recursão. Irônico que esteja no Stack Overflow. stackoverflow.com/q/2805172/265877
Alex

@ Alex, você faz um bom argumento. Em alguns casos, o entrevistador solicitará que você não use Array.prototype.reverse().
Daniel

10

Existem várias maneiras de fazer isso, você pode verificar o seguinte,

1. Tradicional para loop (incrementando):

function reverseString(str){
        let stringRev ="";
        for(let i= 0; i<str.length; i++){
            stringRev = str[i]+stringRev;
        }
        return stringRev;
}
alert(reverseString("Hello World!"));

2. Tradicional para loop (decrescente):

function reverseString(str){
    let revstr = "";
    for(let i = str.length-1; i>=0; i--){
        revstr = revstr+ str[i];
    }
    return revstr;
}
alert(reverseString("Hello World!"));

3. Usando o loop for-of

function reverseString(str){
    let strn ="";
    for(let char of str){
        strn = char + strn;
    }
    return strn;
}
alert(reverseString("Get well soon"));

4. Usando o método de matriz forEach / high order:

function reverseString(str){

  let revSrring = "";
  str.split("").forEach(function(char){
    
    revSrring = char + revSrring;
  
  });
  return revSrring;
}
alert(reverseString("Learning JavaScript"));

5. Norma ES6:

function reverseString(str){

  let revSrring = "";
  str.split("").forEach(char => revSrring = char + revSrring);
  return revSrring;
}
alert(reverseString("Learning JavaScript"));

6. A última maneira:

function reverseString(str){

  return str.split("").reduce(function(revString, char){
       return char + revString;
  }, "");
 
}

alert(reverseString("Learning JavaScript"));

7. Você também pode obter o resultado usando o seguinte,

function reverseString(str){

  return str.split("").reduce((revString, char)=> char + revString, "");
 
}
alert(reverseString("Learning JavaScript"));


7

No ES6, você tem mais uma opção

function reverseString (str) {
  return [...str].reverse().join('')
}

reverseString('Hello');

6

Esta é a maneira mais fácil que eu acho

var reverse = function(str) {
    var arr = [];
    
    for (var i = 0, len = str.length; i <= len; i++) {
        arr.push(str.charAt(len - i))
    }

    return arr.join('');
}

console.log(reverse('I want a 🍺'));


3
É bom que você tenha incluído um emoji no seu exemplo. Para que possamos ver rapidamente que isso claramente não funciona para emojis e muitos outros caracteres unicode.
Íhor Mé 21/07

Fé, enquanto sua resposta está correta, eu discordo que é a maneira mais fácil. As primeiras respostas fazem uso Array.prototype.reverse()dessa seria a maneira mais fácil, daí a resposta mais popular. Obviamente, isso exigiria um bom conhecimento prévio de JavaScript.
Daniel

6
var str = 'sample string';
[].map.call(str, function(x) {
  return x;
}).reverse().join('');

OU

var str = 'sample string';
console.log(str.split('').reverse().join(''));

// Saída: 'gnirts elpmas'


Toda a sua parte do 'mapa' pode ser escrita como [...str].

5

Sei que essa é uma pergunta antiga que foi bem respondida, mas, para minha própria diversão, escrevi a seguinte função reversa e pensei em compartilhá-la caso fosse útil para qualquer outra pessoa. Ele lida com pares substitutos e marcas combinadas:

function StringReverse (str)
{
  var charArray = [];
  for (var i = 0; i < str.length; i++)
    {
      if (i+1 < str.length)
        {
          var value = str.charCodeAt(i);
          var nextValue = str.charCodeAt(i+1);
          if (   (   value >= 0xD800 && value <= 0xDBFF
                  && (nextValue & 0xFC00) == 0xDC00) // Surrogate pair)
              || (nextValue >= 0x0300 && nextValue <= 0x036F)) // Combining marks
            {
              charArray.unshift(str.substring(i, i+2));
              i++; // Skip the other half
              continue;
            }
        }

      // Otherwise we just have a rogue surrogate marker or a plain old character.
      charArray.unshift(str[i]);
    }

  return charArray.join('');
}

Todas as sugestões para Mathias, Punycode e várias outras referências para me ensinar sobre as complexidades da codificação de caracteres em JavaScript.



3

Se você não quiser usar nenhuma função incorporada. Tente isto

var string = 'abcdefg';
var newstring = '';

for(let i = 0; i < string.length; i++){
    newstring = string[i] += newstring;
}

console.log(newstring);

2

A resposta real é: você não pode revertê-lo no lugar, mas pode criar uma nova string que é o inverso.

Assim como um exercício para brincar com a recursão: às vezes, quando você vai a uma entrevista, o entrevistador pode perguntar como fazer isso usando a recursão, e eu acho que a "resposta preferida" pode ser "eu preferiria não fazer isso na recursão, pois pode causar facilmente um estouro de pilha "(porque é O(n)melhor que O(log n). Se for O(log n), é muito difícil obter um estouro de pilha - 4 bilhões de itens podem ser manipulados por um nível de pilha de 32, pois 2 ** 32 é 4294967296. Mas se forO(n) , pode facilmente obter um estouro de pilha.

Às vezes, o entrevistador ainda pergunta: "Apenas como exercício, por que você ainda não o escreve usando recursão?" E aqui está:

String.prototype.reverse = function() {
    if (this.length <= 1) return this;
    else return this.slice(1).reverse() + this.slice(0,1);
}

execução de teste:

var s = "";
for(var i = 0; i < 1000; i++) {
    s += ("apple" + i);
}
console.log(s.reverse());

resultado:

999elppa899elppa...2elppa1elppa0elppa

Para tentar obter um estouro de pilha, mudei 1000para 10000no Google Chrome e ele relatou:

RangeError: Maximum call stack size exceeded

2

As cadeias de caracteres são imutáveis, mas você pode criar facilmente uma cópia invertida com o seguinte código:

function reverseString(str) {

  var strArray = str.split("");
  strArray.reverse();

  var strReverse = strArray.join("");

  return strReverse;
}

reverseString("hello");

2
//es6
//array.from
const reverseString = (string) => Array.from(string).reduce((a, e) => e + a);
//split
const reverseString = (string) => string.split('').reduce((a, e) => e + a); 

//split problem
"𠜎𠺢".split('')[0] === Array.from("𠜎𠺢")[0] // "�" === "𠜎" => false
"😂😹🤗".split('')[0] === Array.from("😂😹🤗")[0] // "�" === "😂" => false

1
Isso tem a vantagem de lidar com caracteres de plano suplementares corretamente.

2

Uma pequena função que lida com caracteres diacríticos e caracteres de 2 bytes:

(function(){
  var isCombiningDiacritic = function( code )
  {
    return (0x0300 <= code && code <= 0x036F)  // Comb. Diacritical Marks
        || (0x1AB0 <= code && code <= 0x1AFF)  // Comb. Diacritical Marks Extended
        || (0x1DC0 <= code && code <= 0x1DFF)  // Comb. Diacritical Marks Supplement
        || (0x20D0 <= code && code <= 0x20FF)  // Comb. Diacritical Marks for Symbols
        || (0xFE20 <= code && code <= 0xFE2F); // Comb. Half Marks

  };

  String.prototype.reverse = function()
  {
    var output = "",
        i      = this.length - 1,
        width;

    for ( ; i >= 0; --i )
    {
      width = 1;
      while( i > 0 && isCombiningDiacritic( this.charCodeAt(i) ) )
      {
        --i;
        width++;
      }

      if (
           i > 0
        && "\uDC00" <= this[i]   && this[i]   <= "\uDFFF"
        && "\uD800" <= this[i-1] && this[i-1] <= "\uDBFF"
      )
      {
        --i;
        width++;
      }

      output += this.substr( i, width );
    }

    return output;
  }
})();

// Tests
[
  'abcdefg',
  'ab\u0303c',
  'a\uD83C\uDFA5b',
  'a\uD83C\uDFA5b\uD83C\uDFA6c',
  'a\uD83C\uDFA5b\u0306c\uD83C\uDFA6d',
  'TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚​N̐Y̡' // copied from http://stackoverflow.com/a/1732454/1509264
].forEach(
  function(str){ console.log( str + " -> " + str.reverse() ); }
);
  


Atualizar

Uma lista mais completa de combinação de diacríticos é:

      var isCombiningDiacritic = function( code )
      {
        return (0x0300 <= code && code <= 0x036F)
            || (0x0483 <= code && code <= 0x0489)
            || (0x0591 <= code && code <= 0x05BD)
            || (code == 0x05BF)
            || (0x05C1 <= code && code <= 0x05C2)
            || (0x05C4 <= code && code <= 0x05C5)
            || (code == 0x05C7)
            || (0x0610 <= code && code <= 0x061A)
            || (0x064B <= code && code <= 0x065F)
            || (code == 0x0670)
            || (0x06D6 <= code && code <= 0x06DC)
            || (0x06DF <= code && code <= 0x06E4)
            || (0x06E7 <= code && code <= 0x06E8)
            || (0x06EA <= code && code <= 0x06ED)
            || (code == 0x0711)
            || (0x0730 <= code && code <= 0x074A)
            || (0x07A6 <= code && code <= 0x07B0)
            || (0x07EB <= code && code <= 0x07F3)
            || (code == 0x07FD)
            || (0x0816 <= code && code <= 0x0819)
            || (0x081B <= code && code <= 0x0823)
            || (0x0825 <= code && code <= 0x0827)
            || (0x0829 <= code && code <= 0x082D)
            || (0x0859 <= code && code <= 0x085B)
            || (0x08D3 <= code && code <= 0x08E1)
            || (0x08E3 <= code && code <= 0x0902)
            || (code == 0x093A)
            || (code == 0x093C)
            || (0x0941 <= code && code <= 0x0948)
            || (code == 0x094D)
            || (0x0951 <= code && code <= 0x0957)
            || (0x0962 <= code && code <= 0x0963)
            || (code == 0x0981)
            || (code == 0x09BC)
            || (0x09C1 <= code && code <= 0x09C4)
            || (code == 0x09CD)
            || (0x09E2 <= code && code <= 0x09E3)
            || (0x09FE <= code && code <= 0x0A02)
            || (code == 0x0A3C)
            || (0x0A41 <= code && code <= 0x0A51)
            || (0x0A70 <= code && code <= 0x0A71)
            || (code == 0x0A75)
            || (0x0A81 <= code && code <= 0x0A82)
            || (code == 0x0ABC)
            || (0x0AC1 <= code && code <= 0x0AC8)
            || (code == 0x0ACD)
            || (0x0AE2 <= code && code <= 0x0AE3)
            || (0x0AFA <= code && code <= 0x0B01)
            || (code == 0x0B3C)
            || (code == 0x0B3F)
            || (0x0B41 <= code && code <= 0x0B44)
            || (0x0B4D <= code && code <= 0x0B56)
            || (0x0B62 <= code && code <= 0x0B63)
            || (code == 0x0B82)
            || (code == 0x0BC0)
            || (code == 0x0BCD)
            || (code == 0x0C00)
            || (code == 0x0C04)
            || (0x0C3E <= code && code <= 0x0C40)
            || (0x0C46 <= code && code <= 0x0C56)
            || (0x0C62 <= code && code <= 0x0C63)
            || (code == 0x0C81)
            || (code == 0x0CBC)
            || (0x0CCC <= code && code <= 0x0CCD)
            || (0x0CE2 <= code && code <= 0x0CE3)
            || (0x0D00 <= code && code <= 0x0D01)
            || (0x0D3B <= code && code <= 0x0D3C)
            || (0x0D41 <= code && code <= 0x0D44)
            || (code == 0x0D4D)
            || (0x0D62 <= code && code <= 0x0D63)
            || (code == 0x0DCA)
            || (0x0DD2 <= code && code <= 0x0DD6)
            || (code == 0x0E31)
            || (0x0E34 <= code && code <= 0x0E3A)
            || (0x0E47 <= code && code <= 0x0E4E)
            || (code == 0x0EB1)
            || (0x0EB4 <= code && code <= 0x0EBC)
            || (0x0EC8 <= code && code <= 0x0ECD)
            || (0x0F18 <= code && code <= 0x0F19)
            || (code == 0x0F35)
            || (code == 0x0F37)
            || (code == 0x0F39)
            || (0x0F71 <= code && code <= 0x0F7E)
            || (0x0F80 <= code && code <= 0x0F84)
            || (0x0F86 <= code && code <= 0x0F87)
            || (0x0F8D <= code && code <= 0x0FBC)
            || (code == 0x0FC6)
            || (0x102D <= code && code <= 0x1030)
            || (0x1032 <= code && code <= 0x1037)
            || (0x1039 <= code && code <= 0x103A)
            || (0x103D <= code && code <= 0x103E)
            || (0x1058 <= code && code <= 0x1059)
            || (0x105E <= code && code <= 0x1060)
            || (0x1071 <= code && code <= 0x1074)
            || (code == 0x1082)
            || (0x1085 <= code && code <= 0x1086)
            || (code == 0x108D)
            || (code == 0x109D)
            || (0x135D <= code && code <= 0x135F)
            || (0x1712 <= code && code <= 0x1714)
            || (0x1732 <= code && code <= 0x1734)
            || (0x1752 <= code && code <= 0x1753)
            || (0x1772 <= code && code <= 0x1773)
            || (0x17B4 <= code && code <= 0x17B5)
            || (0x17B7 <= code && code <= 0x17BD)
            || (code == 0x17C6)
            || (0x17C9 <= code && code <= 0x17D3)
            || (code == 0x17DD)
            || (0x180B <= code && code <= 0x180D)
            || (0x1885 <= code && code <= 0x1886)
            || (code == 0x18A9)
            || (0x1920 <= code && code <= 0x1922)
            || (0x1927 <= code && code <= 0x1928)
            || (code == 0x1932)
            || (0x1939 <= code && code <= 0x193B)
            || (0x1A17 <= code && code <= 0x1A18)
            || (code == 0x1A1B)
            || (code == 0x1A56)
            || (0x1A58 <= code && code <= 0x1A60)
            || (code == 0x1A62)
            || (0x1A65 <= code && code <= 0x1A6C)
            || (0x1A73 <= code && code <= 0x1A7F)
            || (0x1AB0 <= code && code <= 0x1B03)
            || (code == 0x1B34)
            || (0x1B36 <= code && code <= 0x1B3A)
            || (code == 0x1B3C)
            || (code == 0x1B42)
            || (0x1B6B <= code && code <= 0x1B73)
            || (0x1B80 <= code && code <= 0x1B81)
            || (0x1BA2 <= code && code <= 0x1BA5)
            || (0x1BA8 <= code && code <= 0x1BA9)
            || (0x1BAB <= code && code <= 0x1BAD)
            || (code == 0x1BE6)
            || (0x1BE8 <= code && code <= 0x1BE9)
            || (code == 0x1BED)
            || (0x1BEF <= code && code <= 0x1BF1)
            || (0x1C2C <= code && code <= 0x1C33)
            || (0x1C36 <= code && code <= 0x1C37)
            || (0x1CD0 <= code && code <= 0x1CD2)
            || (0x1CD4 <= code && code <= 0x1CE0)
            || (0x1CE2 <= code && code <= 0x1CE8)
            || (code == 0x1CED)
            || (code == 0x1CF4)
            || (0x1CF8 <= code && code <= 0x1CF9)
            || (0x1DC0 <= code && code <= 0x1DFF)
            || (0x20D0 <= code && code <= 0x20F0)
            || (0x2CEF <= code && code <= 0x2CF1)
            || (code == 0x2D7F)
            || (0x2DE0 <= code && code <= 0x2DFF)
            || (0x302A <= code && code <= 0x302D)
            || (0x3099 <= code && code <= 0x309A)
            || (0xA66F <= code && code <= 0xA672)
            || (0xA674 <= code && code <= 0xA67D)
            || (0xA69E <= code && code <= 0xA69F)
            || (0xA6F0 <= code && code <= 0xA6F1)
            || (code == 0xA802)
            || (code == 0xA806)
            || (code == 0xA80B)
            || (0xA825 <= code && code <= 0xA826)
            || (0xA8C4 <= code && code <= 0xA8C5)
            || (0xA8E0 <= code && code <= 0xA8F1)
            || (code == 0xA8FF)
            || (0xA926 <= code && code <= 0xA92D)
            || (0xA947 <= code && code <= 0xA951)
            || (0xA980 <= code && code <= 0xA982)
            || (code == 0xA9B3)
            || (0xA9B6 <= code && code <= 0xA9B9)
            || (0xA9BC <= code && code <= 0xA9BD)
            || (code == 0xA9E5)
            || (0xAA29 <= code && code <= 0xAA2E)
            || (0xAA31 <= code && code <= 0xAA32)
            || (0xAA35 <= code && code <= 0xAA36)
            || (code == 0xAA43)
            || (code == 0xAA4C)
            || (code == 0xAA7C)
            || (code == 0xAAB0)
            || (0xAAB2 <= code && code <= 0xAAB4)
            || (0xAAB7 <= code && code <= 0xAAB8)
            || (0xAABE <= code && code <= 0xAABF)
            || (code == 0xAAC1)
            || (0xAAEC <= code && code <= 0xAAED)
            || (code == 0xAAF6)
            || (code == 0xABE5)
            || (code == 0xABE8)
            || (code == 0xABED)
            || (code == 0xFB1E)
            || (0xFE00 <= code && code <= 0xFE0F)
            || (0xFE20 <= code && code <= 0xFE2F)
            || (code == 0x101FD)
            || (code == 0x102E0)
            || (0x10376 <= code && code <= 0x1037A)
            || (0x10A01 <= code && code <= 0x10A0F)
            || (0x10A38 <= code && code <= 0x10A3F)
            || (0x10AE5 <= code && code <= 0x10AE6)
            || (0x10D24 <= code && code <= 0x10D27)
            || (0x10F46 <= code && code <= 0x10F50)
            || (code == 0x11001)
            || (0x11038 <= code && code <= 0x11046)
            || (0x1107F <= code && code <= 0x11081)
            || (0x110B3 <= code && code <= 0x110B6)
            || (0x110B9 <= code && code <= 0x110BA)
            || (0x11100 <= code && code <= 0x11102)
            || (0x11127 <= code && code <= 0x1112B)
            || (0x1112D <= code && code <= 0x11134)
            || (code == 0x11173)
            || (0x11180 <= code && code <= 0x11181)
            || (0x111B6 <= code && code <= 0x111BE)
            || (0x111C9 <= code && code <= 0x111CC)
            || (0x1122F <= code && code <= 0x11231)
            || (code == 0x11234)
            || (0x11236 <= code && code <= 0x11237)
            || (code == 0x1123E)
            || (code == 0x112DF)
            || (0x112E3 <= code && code <= 0x112EA)
            || (0x11300 <= code && code <= 0x11301)
            || (0x1133B <= code && code <= 0x1133C)
            || (code == 0x11340)
            || (0x11366 <= code && code <= 0x11374)
            || (0x11438 <= code && code <= 0x1143F)
            || (0x11442 <= code && code <= 0x11444)
            || (code == 0x11446)
            || (code == 0x1145E)
            || (0x114B3 <= code && code <= 0x114B8)
            || (code == 0x114BA)
            || (0x114BF <= code && code <= 0x114C0)
            || (0x114C2 <= code && code <= 0x114C3)
            || (0x115B2 <= code && code <= 0x115B5)
            || (0x115BC <= code && code <= 0x115BD)
            || (0x115BF <= code && code <= 0x115C0)
            || (0x115DC <= code && code <= 0x115DD)
            || (0x11633 <= code && code <= 0x1163A)
            || (code == 0x1163D)
            || (0x1163F <= code && code <= 0x11640)
            || (code == 0x116AB)
            || (code == 0x116AD)
            || (0x116B0 <= code && code <= 0x116B5)
            || (code == 0x116B7)
            || (0x1171D <= code && code <= 0x1171F)
            || (0x11722 <= code && code <= 0x11725)
            || (0x11727 <= code && code <= 0x1172B)
            || (0x1182F <= code && code <= 0x11837)
            || (0x11839 <= code && code <= 0x1183A)
            || (0x119D4 <= code && code <= 0x119DB)
            || (code == 0x119E0)
            || (0x11A01 <= code && code <= 0x11A06)
            || (0x11A09 <= code && code <= 0x11A0A)
            || (0x11A33 <= code && code <= 0x11A38)
            || (0x11A3B <= code && code <= 0x11A3E)
            || (code == 0x11A47)
            || (0x11A51 <= code && code <= 0x11A56)
            || (0x11A59 <= code && code <= 0x11A5B)
            || (0x11A8A <= code && code <= 0x11A96)
            || (0x11A98 <= code && code <= 0x11A99)
            || (0x11C30 <= code && code <= 0x11C3D)
            || (0x11C92 <= code && code <= 0x11CA7)
            || (0x11CAA <= code && code <= 0x11CB0)
            || (0x11CB2 <= code && code <= 0x11CB3)
            || (0x11CB5 <= code && code <= 0x11CB6)
            || (0x11D31 <= code && code <= 0x11D45)
            || (code == 0x11D47)
            || (0x11D90 <= code && code <= 0x11D91)
            || (code == 0x11D95)
            || (code == 0x11D97)
            || (0x11EF3 <= code && code <= 0x11EF4)
            || (0x16AF0 <= code && code <= 0x16AF4)
            || (0x16B30 <= code && code <= 0x16B36)
            || (code == 0x16F4F)
            || (0x16F8F <= code && code <= 0x16F92)
            || (0x1BC9D <= code && code <= 0x1BC9E)
            || (0x1D167 <= code && code <= 0x1D169)
            || (0x1D17B <= code && code <= 0x1D182)
            || (0x1D185 <= code && code <= 0x1D18B)
            || (0x1D1AA <= code && code <= 0x1D1AD)
            || (0x1D242 <= code && code <= 0x1D244)
            || (0x1DA00 <= code && code <= 0x1DA36)
            || (0x1DA3B <= code && code <= 0x1DA6C)
            || (code == 0x1DA75)
            || (code == 0x1DA84)
            || (0x1DA9B <= code && code <= 0x1E02A)
            || (0x1E130 <= code && code <= 0x1E136)
            || (0x1E2EC <= code && code <= 0x1E2EF)
            || (0x1E8D0 <= code && code <= 0x1E8D6)
            || (0x1E944 <= code && code <= 0x1E94A)
            || (0xE0100 <= code && code <= 0xE01EF);
      };

Uma tentativa digna, mas se você digitalizar o arquivo UnicodeData.txt, descobrirá que existem 316 desses intervalos de combinação de diacríticos, em vez de 5.
Sr. Lister

@MrLister A solução é editar a isCombiningDiacriticfunção para incluir todos os 316 intervalos; fique à vontade para fornecer essa edição, pois você parece ter os dados disponíveis.
MT0 04/02

1
function reverseString(string) {
    var reversedString = "";
    var stringLength = string.length - 1;
    for (var i = stringLength; i >= 0; i--) {
        reversedString += string[i];
    }
    return reversedString;
}

1

sem converter string em array;

String.prototype.reverse = function() {

    var ret = "";
    var size = 0;

    for (var i = this.length - 1; -1 < i; i -= size) {

        if (
          '\uD800' <= this[i - 1] && this[i - 1] <= '\uDBFF' && 
          '\uDC00' <= this[i]     && this[i]     <= '\uDFFF'
        ) {
            size = 2;
            ret += this[i - 1] + this[i];
        } else {
            size = 1;
            ret += this[i];
        }
    }

    return ret;
}

console.log('anãnam anañam' === 'mañana mañana'.reverse());

usando Array.reverse sem converter caracteres em pontos de código;

String.prototype.reverse = function() {

    var array = this.split("").reverse();

    for (var i = 0; i < this.length; ++i) {

        if (
          '\uD800' <= this[i - 1] && this[i - 1] <= '\uDBFF' && 
          '\uDC00' <= this[i]     && this[i]     <= '\uDFFF'
        ) {
            array[i - 1] = array[i - 1] + array[i];
            array[i] = array[i - 1].substr(0, 1);
            array[i - 1] = array[i - 1].substr(1, 1);
        }

    }

    return array.join("");
}

console.log('anãnam anañam' === 'mañana mañana'.reverse());

Para a segunda versão: var c = array[i-1]; array[i-1] = array[i]; array[i] = c;não requer concatenação do par de códigos. Além disso, o loop for deve começar em 1.
MT0

A segunda versão não funciona '\ud83c\ud83c\udfa5'.reverse()- ela produzirá o mesmo que a entrada. A adição ++i;na ifinstrução deve corrigir isso.
MT0 09/01

Pensando bem - isso não lida com a combinação de diacríticos: 'a\u0303bc'.reverse() === 'cba\u0303'deve retornar verdadeiro.
MT0 9/01/19

1

Eu acho que String.prototype.reverse é uma boa maneira de resolver esse problema; o código como abaixo;

String.prototype.reverse = function() {
  return this.split('').reverse().join('');
}

var str = 'this is a good example for string reverse';
str.reverse();
-> "esrever gnirts rof elpmaxe doog a si siht";

1

Usando funções Array,

String.prototype.reverse = function(){
    return [].reduceRight.call(this, function(last, secLast){return last + secLast});
}

1
var str = "my name is saurabh ";
var empStr='',finalString='';
var chunk=[];
function reverse(str){
var i,j=0,n=str.length;
    for(i=0;i<n;++i){
        if(str[i]===' '){
            chunk[j]=empStr;
            empStr = '';
            j++;
        }else{
            empStr=empStr+str[i];
        }
    }
    for(var z=chunk.length-1;z>=0;z--){
        finalString = finalString +' '+ chunk[z];
        console.log(finalString);
    }
    return true;
}
reverse(str);

Como é isso "no lugar"?
Sudhansu Choudhary

1

Minha própria tentativa original ...

var str = "The Car";

function reverseStr(str) {
  var reversed = "";
  var len = str.length;
  for (var i = 1; i < (len + 1); i++) {  
    reversed += str[len - i];      
  }

  return reversed;
}

var strReverse = reverseStr(str);    
console.log(strReverse);
// "raC ehT"

http://jsbin.com/bujiwo/19/edit?js,console,output


1

Mantenha-o seco e simples bobo !!

function reverse(s){
let str = s;
var reverse = '';
for (var i=str.length;i>0;i--){

    var newstr = str.substring(0,i)
    reverse += newstr.substr(-1,1)
}
return reverse;
}

1

OK, bem simples, você pode criar uma função com um loop simples para fazer a string inversa sem usar reverse(), charAt()etc , como este:

Por exemplo, você tem esta sequência:

var name = "StackOverflow";

Crie uma função como essa, eu chamo de reverseString...

function reverseString(str) {
  if(!str.trim() || 'string' !== typeof str) {
    return;
  }
  let l=str.length, s='';
  while(l > 0) {
    l--;
    s+= str[l];
  }
  return s;
}

E você pode chamar assim:

reverseString(name);

E o resultado será:

"wolfrevOkcatS"

1

Melhores maneiras de reverter uma string em JavaScript

1) Array.reverse:

Você provavelmente está pensando, espere, pensei que estávamos revertendo uma string, por que você está usando o método Array.reverse. Usando o método String.split, estamos convertendo nossa string em uma matriz de caracteres. Então, estamos revertendo a ordem de cada valor na matriz e, finalmente, convertemos a matriz de volta em uma String usando o método Array.join.

function reverseString(str) {
    return str.split('').reverse().join('');
}
reverseString('dwayne');

2) Decrementando o loop while:

Embora bem detalhada, esta solução tem vantagens sobre a solução um. Você não está criando uma matriz e apenas concatenando uma sequência com base em caracteres da sequência de origem.

De uma perspectiva de desempenho, esse provavelmente traria os melhores resultados (embora não testado). Para seqüências extremamente longas, os ganhos de desempenho podem cair pela janela.

function reverseString(str) {
    var temp = '';
    var i = str.length;

    while (i > 0) {
        temp += str.substring(i - 1, i);
        i--;
    }


    return temp;
}
reverseString('dwayne');

3) Recursão

Eu amo como esta solução é simples e clara. Você pode ver claramente que os métodos String.charAt e String.substr estão sendo usados ​​para passar por um valor diferente chamando a si próprio todas as vezes até que a string esteja vazia, da qual o ternário retornaria uma string vazia em vez de usar a recursão para chamar a si mesma. . Provavelmente, isso renderia o segundo melhor desempenho após a segunda solução.

function reverseString(str) {
    return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.