¿Cómo invierte una cadena en su lugar en JavaScript?


435

¿Cómo invierte una cadena en su lugar (o in situ) en JavaScript cuando se pasa a una función con una declaración de retorno, sin usar las funciones integradas ( .reverse(), .charAt()etc.)?


entonces, ¿no puedes usar .charAt () para obtener los caracteres de la cadena?
Irwin

155
No puedes Las cadenas de JavaScript son inmutables, lo que significa que no se puede escribir en la memoria asignada a cada una, lo que hace que las verdaderas reversiones "en el lugar" sean imposibles.
Crescent Fresh

2
Re: crescentfresh comentario ver stackoverflow.com/questions/51185/…
baudtack

1
@crescentfresh debe publicar eso como una nueva respuesta.
baudtack

Respuestas:


737

Mientras trabaje con caracteres ASCII simples, y esté contento de usar las funciones integradas, esto funcionará:

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

Si necesita una solución que admita UTF-16 u otros caracteres de varios bytes, tenga en cuenta que esta función proporcionará cadenas Unicode no válidas o cadenas válidas que parecen divertidas. Es posible que desee considerar esta respuesta en su lugar .

[... s] es consciente de Unicode, una pequeña edición da: -

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

44
Esto se rompe para las cadenas UTF-16 que contienen pares sustitutos, es decir, caracteres fuera del plano multilingüe básico. También dará resultados divertidos para las cadenas que contienen caracteres combinados, por ejemplo, puede aparecer una diéresis en el siguiente carácter. El primer problema conducirá a cadenas Unicode no válidas, el segundo a cadenas válidas que parecen divertidas.
Martin Probst

2
@Richeve Bebedor "¿Todo sin usar las funciones integradas? .Reverse ()" Esta no sería una solución aceptada ya que no cabe dentro de los límites de la pregunta, a pesar de ser una solución viable para invertir una cadena en JS.
David Starkey

1
@DavidStarkey: Sí, recordando esto casi cuatro años después, es difícil ver cómo me perdí el punto de la pregunta. ¡Parece que debería haber esperado dos minutos y haber votado por el comentario de Crescentfresh en la publicación original!
belacqua

14
@MartinProbst Mi respuesta proporciona una solución Unicode para el problema que trata con pares sustitutos y combinando marcas correctamente: stackoverflow.com/a/16776380/96656
Mathias Bynens

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

411

La siguiente técnica (o similar) se usa comúnmente para invertir una cadena en JavaScript:

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

De hecho, todas las respuestas publicadas hasta ahora son una variación de este patrón. Sin embargo, hay algunos problemas con esta solución. Por ejemplo:

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

Si te preguntas por qué sucede esto, lea sobre la codificación de caracteres interna de JavaScript . (TL; DR: 𝌆es un símbolo astral, y JavaScript lo expone como dos unidades de código separadas).

Pero hay más:

// 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.

Una buena cadena para probar implementaciones inversas de cadena es la siguiente :

'foo 𝌆 bar mañana mañana'

¿Por qué? Porque contiene un símbolo astral ( 𝌆) (que están representados por pares sustitutos en JavaScript ) y una marca de combinación ( el últimomañana realidad consta de dos símbolos: U + 006E LETRA PEQUEÑA LATINA N y U + 0303 TILDE COMBINADO).

El orden en que aparecen los pares sustitutos no se puede invertir, de lo contrario, el símbolo astral ya no aparecerá en la cadena 'invertida'. Por eso viste esos�� marcas en la salida del ejemplo anterior.

Las marcas combinadas siempre se aplican al símbolo anterior, por lo que debe tratar tanto el símbolo principal (U + 006E LETRA PEQUEÑA LATINA N) como la marca combinada (U + 0303 TILDE COMBINADA) como un todo. Invertir su orden hará que la marca de combinación se empareje con otro símbolo en la cadena. Es por eso que la salida de ejemplo tenía lugar de ñ.

Con suerte, esto explica por qué todas las respuestas publicadas hasta ahora son incorrectas .


Para responder a su pregunta inicial ( cómo invertir [correctamente] una cadena en JavaScript ), he escrito una pequeña biblioteca de JavaScript que es capaz de revertir cadenas con reconocimiento Unicode. No tiene ninguno de los problemas que acabo de mencionar. La biblioteca se llama Esrever. ; su código está en GitHub y funciona en prácticamente cualquier entorno de JavaScript. Viene con una utilidad / binario de shell, por lo que puede invertir fácilmente las cadenas de su terminal si lo desea.

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

En cuanto a la parte "en el lugar", vea las otras respuestas.


65
Debe incluir la parte principal del código de Esrever en su respuesta.
r0estir0bbe

1
@Meglio Con ese enfoque específico, sí.
Mathias Bynens

8
El problema, por supuesto, es que "invertir una cadena" suena inequívoco, pero no se trata de los problemas mencionados aquí. ¿Invertir una cadena devuelve la cadena que, cuando se imprima, mostrará los grupos de grafemas en la cadena en orden inverso? Por un lado, eso suena probable. Por otro lado, ¿por qué querrías hacer eso? Esta definición depende de que se imprima, y ​​la impresión de una cadena invertida rara vez es útil. Como parte de un algoritmo, sus requisitos pueden ser completamente diferentes.
Martijn

19
Si bien esto hace un gran trabajo al explicar el problema, la respuesta real está en otro castillo . Como @ r0estir0bbe dijo hace más de un año, el código relevante debería estar en la respuesta, no solo vinculado.
TJ Crowder

44
"Esperemos que esto explique por qué todas las respuestas publicadas hasta ahora son incorrectas". Esta afirmación es demasiado contundente. Muchos casos de uso no requieren compatibilidad con UTF-16 (ejemplo simple; trabajar con URL y componentes / parámetros de URL). Una solución no es "incorrecta" simplemente porque no maneja un escenario no requerido. En particular, la respuesta más votada declara explícitamente que solo funciona con caracteres ASCII y, por lo tanto, definitivamente ni siquiera está un poco equivocado.
Aroth

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

o

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

Definitivamente estoy de acuerdo con el prototipo de cadena.
Jeff Meatball Yang

3
la concatenación de cadenas es costosa. Es mejor construir una matriz y unirla o usar concat ().
Bjorn

2
# 1 es mejor, # 2 podría ser horriblemente lento
adamJLev

99
Sin embargo, ninguna de las soluciones funciona cuando hay caracteres compuestos Unicode.
Eric Grange

2
@JuanMendes Dejé ese comentario en 2009, las cosas han cambiado en los últimos 4 años. : P
Bjorn

63

Análisis detallado y diez formas diferentes de invertir una cadena y sus detalles de rendimiento.

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

Rendimiento de estas implementaciones:

Implementación (es) de mejor rendimiento por navegador

  • Chrome 15: implementaciones 1 y 6
  • Firefox 7 - Implementación 6
  • IE 9 - Implementación 4
  • Opera 12 - Implementación 9

Aquí están esas implementaciones:

Implementación 1:

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

Implementación 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('');
}

Implementación 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('');
}

Implementación 4:

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

Implementación 5:

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

Implementación 6:

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

Implementación 7:

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

Implementación 8:

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

Implementación 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('');
    }

Implementación 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 el "revertir una cadena en el lugar" es una pregunta de entrevista anticuada que los programadores de C, y las personas que fueron entrevistadas por ellos (¿por venganza, tal vez?), Preguntarán. Desafortunadamente, es la parte "In Place" que ya no funciona porque las cadenas en casi cualquier lenguaje administrado (JS, C #, etc.) usan cadenas inmutables, lo que anula la idea de mover una cadena sin asignar memoria nueva.

Si bien las soluciones anteriores sí invierten una cadena, no lo hacen sin asignar más memoria y, por lo tanto, no satisfacen las condiciones. Debe tener acceso directo a la cadena asignada y poder manipular su ubicación de memoria original para poder revertirla en su lugar.

Personalmente, realmente odio este tipo de preguntas de entrevistas, pero lamentablemente, estoy seguro de que las seguiremos viendo en los próximos años.


77
Al menos puedo decir que tuve un entrevistador hace un tiempo que me impresionó bastante cuando me preguntó cómo invertir una cadena "en el lugar" en JS y le expliqué por qué es imposible ya que las cadenas en JS son inmutables. No sé si esa fue la respuesta que esperaba o si lo eduqué un poco. De cualquier manera funcionó bien;)
Chev

1
¿Quizás quiere decir "administrado" por un recolector de basura, al menos eso es lo que generalmente se entiende por "lenguaje administrado" o la presencia de una máquina virtual / entorno de tiempo de ejecución virtual? @torazaburo
AntonB

39

Primero, use Array.from()para convertir una cadena en una matriz, luego Array.prototype.reverse()para invertir la matriz y luego Array.prototype.join()para volverla una cadena.

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

Tiene gastos generales, ¡pero esta es una solución elegante! No hay reescritura de la reverselógica preexistente .
Gershom

2
@felixfbecker No, string.split('')no funciona. Vea esta respuesta para más explicaciones.
Michał Perłakowski el

55
Esta debería ser la respuesta aceptada porque también funciona con Unicode. Por ejemplo, del ejemplo anterior:Array.from('foo 𝌆 bar mañana mañana').reverse().join('') == 'anãnam anañam rab 𝌆 oof'
Julian TF

3
@JulianTF No exactamente, todavía se aplica una tilde a 'a' en lugar de 'n'.
Roman Boiko

2
@RomanBoiko True, pero puedes normalizar la cadena primero. Array.from('foo 𝌆 bar mañana mañana'.normalize('NFC')).reverse().join('')se convertirá"anañam anañam rab 𝌆 oof"
Sr. Lister

26

En ECMAScript 6, puede invertir una cadena aún más rápido sin usar el .split('')método de división, con el operador de propagación de la siguiente manera:

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

1
ES6 también le permite usar dos backticks `` en lugar de('')

no hay razón para usar dos backticks en este caso
Vic

1
A menos que sea golf de código, debe evitar esto. Escribir string.split('')es más claro para la mayoría de las personas que [...string].
AnnanFay

1
@AnnanFay .split('')tiene el problema con los caracteres de los planos suplementarios (pares sustitutos en UTF-16), porque se divide por unidad de código UTF-16 en lugar de punto de código . El operador de propagación y Array.from()(mi preferencia) no lo hacen.
Inkling

@Inkling No me di cuenta de que era un problema. Gracias por mencionarlo. Todavía estaría tentado a escribir una función de utilidad para mayor claridad.
AnnanFay

19

Parece que llego 3 años tarde a la fiesta ...

Lamentablemente no puede, como se ha señalado. Ver ¿Son las cadenas de JavaScript inmutables? ¿Necesito un "generador de cadenas" en JavaScript?

Lo mejor que puede hacer es crear una "vista" o "envoltorio", que tome una cadena y vuelva a implementar cualquier parte de la API de cadena que esté utilizando, pero simulando que la cadena se invierte. Por ejemplo:

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

Manifestación:

> 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"

El pateador: lo siguiente se hace en el lugar por pura matemática, visitando a cada personaje solo una vez, y solo si es necesario:

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

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

Esto produce ahorros significativos si se aplica a una cadena muy grande, si solo está tomando una porción relativamente pequeña de la misma.

El hecho de que esto valga la pena (la reversión como una copia, como en la mayoría de los lenguajes de programación) depende en gran medida de su caso de uso y de la eficiencia con la que vuelva a implementar la API de cadena. Por ejemplo, si todo lo que desea es manipular el índice de la cadena, o tomar pequeños slices o substrs, esto le ahorrará espacio y tiempo. Sin embargo, si planea imprimir grandes segmentos o subcadenas invertidas, los ahorros pueden ser pequeños, incluso peor que haber hecho una copia completa. Su cadena "invertida" tampoco tendrá el tipo string, aunque es posible que pueda fingir esto con la creación de prototipos.

La implementación de demostración anterior crea un nuevo objeto de tipo ReversedString. Tiene un prototipo y, por lo tanto, es bastante eficiente, con un trabajo casi mínimo y una sobrecarga de espacio mínima (se comparten las definiciones de los prototipos). Es una implementación perezosa que implica un corte diferido. Cada vez que realice una función como .sliceo .reversed, realizará matemáticas de índice. Finalmente cuando extrae datos (llamando implícitamente .toString()o.charCodeAt(...) o algo así), se aplicará a los de una manera "inteligente", tocando los mínimos datos posibles.

Nota: la API de cadena anterior es un ejemplo, y puede no implementarse perfectamente. También puede usar solo 1-2 funciones que necesita.


13

Hay muchas formas de invertir una cadena en JavaScript. Estoy anotando tres formas que prefiero.

Enfoque 1: Uso de la función inversa:

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

Enfoque 2: Recorriendo los personajes:

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

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

  return reversed;
}

Enfoque 3: Uso de la función de reducción:

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

Espero que esto ayude :)


10

Durante una entrevista, me pidieron que invirtiera una cadena sin usar ninguna variable o método nativo. Esta es mi implementación favorita:

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

Corto, simple, pero lento como el infierno;)
Tom

13
¿Cero métodos nativos? ¿Qué hay de slice? : - /
hoja

1
Interesante uso de la recursividad. Irónico que está en Stack Overflow. stackoverflow.com/q/2805172/265877
Alex

@ Alex, haces un buen punto. En algunos casos, el entrevistador le pedirá que no lo use Array.prototype.reverse().
Daniel

10

Hay varias formas de hacerlo, puede verificar lo siguiente,

1. Tradicional para bucle (incremental):

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 bucle (decremento):

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 for-of loop

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

4. Usando el 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. La última forma:

function reverseString(str){

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

alert(reverseString("Learning JavaScript"));

7. También puede obtener el resultado usando lo siguiente,

function reverseString(str){

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


7

En ES6, tienes una opción más

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

reverseString('Hello');

6

Esta es la forma más fácil que creo.

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
Es bueno que hayas incluido un emoji en tu ejemplo. Para que podamos ver rápidamente que esto claramente no funciona para emojis y muchos otros caracteres unicode.
Íhor Mé

Fe, aunque tu respuesta es correcta, no estoy de acuerdo con que sea la forma más fácil. Las primeras respuestas hacen uso de Array.prototype.reverse()eso sería la forma más fácil, de ahí la respuesta más popular. Por supuesto, requeriría un buen conocimiento previo de JavaScript.
Daniel

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

O

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

// Salida: 'gnirts elpmas'


Toda su parte 'mapa' se puede escribir como [...str].

5

Sé que esta es una vieja pregunta que ha sido bien respondida, pero para mi propia diversión escribí la siguiente función inversa y pensé que la compartiría en caso de que fuera útil para cualquier otra persona. Maneja ambos pares sustitutos y 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('');
}

Todos los accesorios para Mathias, Punycode y varias otras referencias para enseñarme sobre las complejidades de la codificación de caracteres en JavaScript.



3

Si no desea utilizar ninguna función integrada. Prueba esto

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

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

console.log(newstring);

2

La respuesta real es: no puede revertirlo en su lugar, pero puede crear una nueva cadena que sea la inversa.

Solo como un ejercicio para jugar con la recursividad: a veces, cuando vas a una entrevista, el entrevistador puede preguntarte cómo hacer esto usando la recursividad, y creo que la "respuesta preferida" podría ser "Prefiero no hacerlo en la recursión ya que puede causar fácilmente un desbordamiento de la pila "(porque es O(n)más que O(log n). Si es así O(log n), es bastante difícil obtener un desbordamiento de la pila: un nivel de pila de 32 podría manejar 4 mil millones de elementos, ya que 2 ** 32 es 4294967296. Pero si es así O(n), entonces puede obtener fácilmente un desbordamiento de pila.

A veces, el entrevistador aún te preguntará, "solo como ejercicio, ¿por qué no lo escribes usando la recursividad?" Y aquí está:

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

prueba de funcionamiento:

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

salida:

999elppa899elppa...2elppa1elppa0elppa

Para intentar obtener un desbordamiento de la pila, cambié 1000a 10000Google Chrome e informó:

RangeError: Maximum call stack size exceeded

2

Las cadenas en sí son inmutables, pero puede crear fácilmente una copia invertida con el siguiente 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
Esto tiene la ventaja de que maneja los caracteres del plano suplementario correctamente.

2

Una pequeña función que maneja tanto la combinación de diacríticos como los 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() ); }
);
  


Actualizar

Una lista más completa de combinación de diacríticos es:

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

Un intento digno, pero si escaneara el archivo UnicodeData.txt, encontraría que hay 316 de esos rangos de combinación de diacríticos, en lugar de 5.
Sr. Lister,

@MrLister La solución es editar la isCombiningDiacriticfunción para incluir todos los rangos 316; no dude en proporcionar esa edición, ya que parece tener los datos a mano.
MT0

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

1

sin convertir una cadena en una matriz;

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 sin convertir caracteres en puntos 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 la segunda versión: var c = array[i-1]; array[i-1] = array[i]; array[i] = c;no requiere concatenar el par de códigos. Además, el ciclo for debería comenzar en 1.
MT0

La segunda versión no funciona '\ud83c\ud83c\udfa5'.reverse(): generará lo mismo que la entrada. Agregar ++i;dentro de la ifdeclaración debería solucionar esto.
MT0

Pensándolo bien, esto no maneja la combinación de signos diacríticos: 'a\u0303bc'.reverse() === 'cba\u0303'debería ser verdadero.
MT0

1

Creo que String.prototype.reverse es una buena manera de resolver este problema; el código de la siguiente manera;

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 funciones de matriz,

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

¿Cómo es esto "en su lugar"?
Sudhansu Choudhary

1

Mi propio intento 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

¡Manténgalo SECO y simple tonto!

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, bastante simple, puedes crear una función con un bucle simple para hacer que la cadena se invierta sin usar reverse(), charAt()etc. , así:

Por ejemplo, tienes esta cadena:

var name = "StackOverflow";

Crea una función como esta, lo llamo 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;
}

Y puedes llamarlo así:

reverseString(name);

Y el resultado será:

"wolfrevOkcatS"

1

Las mejores formas de revertir una cadena en JavaScript

1) Array.reverse:

Probablemente estés pensando, espera, pensé que estábamos invirtiendo una cadena, ¿por qué estás usando el método Array.reverse? Usando el método String.split estamos convirtiendo nuestra cadena en una matriz de caracteres. Luego estamos invirtiendo el orden de cada valor en la matriz y finalmente convertimos la matriz nuevamente en una cadena usando el método Array.join.

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

2) Disminución del ciclo while:

Aunque bastante detallada, esta solución tiene sus ventajas sobre la solución uno. No está creando una matriz y solo está concatenando una cadena basada en caracteres de la cadena de origen.

Desde una perspectiva de rendimiento, este probablemente arrojaría los mejores resultados (aunque no probado). Sin embargo, para cadenas extremadamente largas, las ganancias de rendimiento pueden caerse por la ventana.

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

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


    return temp;
}
reverseString('dwayne');

3) recursividad

Me encanta lo simple y clara que es esta solución. Puede ver claramente que los métodos String.charAt y String.substr se están utilizando para pasar a través de un valor diferente al llamarse cada vez hasta que la cadena esté vacía, de lo cual el ternario simplemente devolvería una cadena vacía en lugar de usar la recursión para llamarse . Esto probablemente produciría el segundo mejor rendimiento después de la segunda solución.

function reverseString(str) {
    return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.