Come si inverte una stringa in posizione in JavaScript?

Come si inverte una stringa sul posto (o sul posto) in JavaScript quando viene passata a una funzione con un’istruzione return? Tutto senza utilizzare le funzioni integrate? .reverse() , .charAt() , ecc.

Finché hai a che fare con semplici caratteri ASCII, e sei felice di utilizzare le funzioni integrate, questo funzionerà:

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

Se hai bisogno di una soluzione che supporti UTF-16 o altri caratteri multi-byte, tieni presente che questa funzione fornirà stringhe unicode non valide o stringhe valide che sembrano divertenti. Potresti prendere in considerazione questa risposta .

La seguente tecnica (o simile) è comunemente usata per invertire una stringa in JavaScript:

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

In effetti, tutte le risposte postate finora sono una variazione di questo modello. Tuttavia, ci sono alcuni problemi con questa soluzione. Per esempio:

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

Se ti stai chiedendo perché questo accada, leggi la codifica interna dei caratteri di JavaScript . (TL; DR: 𝌆 è un simbolo astrale e JavaScript lo espone come due unità di codice separate.)

Ma c’è di più:

 // 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 buona stringa per testare le implementazioni inverse di stringhe è la seguente :

 'foo 𝌆 bar mañana mañana' 

Perché? Perché contiene un simbolo astrale ( 𝌆 ) (che sono rappresentati da coppie surrogate in JavaScript ) e un segno di combinazione (il nell’ultimo mañana realtà consiste di due simboli: U + 006E LATIN SMALL LETTER N e U + 0303 COMBINING TILDE) .

L’ordine in cui appaiono le coppie di sostituti non può essere invertito, altrimenti il ​​simbolo astrale non verrà più visualizzato nella stringa “invertita”. Ecco perché hai visto quei segni in nell’output dell’esempio precedente.

La combinazione di segni viene sempre applicata al simbolo precedente, quindi è necessario considerare sia il simbolo principale (U + 006E LATIN SMALL LETTER N) come il simbolo di combinazione (U + 0303 COMBINING TILDE) nel suo complesso. Invertire il loro ordine farà sì che il segno di combinazione venga abbinato a un altro simbolo nella stringa. Ecco perché l’output di esempio aveva invece di ñ .

Spero che questo spieghi perché tutte le risposte postate finora siano sbagliate .


Per rispondere alla tua domanda iniziale – come [correttamente] invertire una stringa in JavaScript -, ho scritto una piccola libreria JavaScript che è in grado di inversione di stringhe in grado di riconoscere Unicode. Non ha nessuno dei problemi che ho appena menzionato. La biblioteca si chiama Esrever ; il suo codice è su GitHub e funziona praticamente in qualsiasi ambiente JavaScript. Viene fornito con un programma di utilità / binario di shell, quindi è ansible invertire facilmente le stringhe dal terminale se lo si desidera.

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

Per quanto riguarda la parte “in-place”, vedi le altre risposte.

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

o

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

L’intero “invertire una stringa sul posto” è un antiquato interrogatore C, i programmatori, e le persone che sono state intervistate da loro (per vendetta, forse?), Chiederanno. Sfortunatamente, è la parte “In Place” che non funziona più perché le stringhe in quasi tutti i linguaggi gestiti (JS, C #, ecc.) Utilizzano stringhe immutabili, sconfiggendo così l’idea di spostare una stringa senza allocare alcuna nuova memoria.

Mentre le soluzioni sopra riportate invero invero una stringa, esse non lo fanno senza allocare più memoria e quindi non soddisfano le condizioni. È necessario avere accesso diretto alla stringa come allocata ed essere in grado di manipolare la sua posizione di memoria originale per poterlo invertire.

Personalmente, odio davvero questo tipo di domande per l’intervista, ma purtroppo sono sicuro che continueremo a vederle per gli anni a venire.

Analisi dettagliate e dieci diversi modi per invertire una stringa e i dettagli delle prestazioni.

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

Perfomance di queste implementazioni:

Implementazione (i) migliore per browser

  • Chrome 15 – Implemations 1 e 6
  • Firefox 7 – Implementazione 6
  • IE 9 – Implementazione 4
  • Opera 12 – Implementazione 9

Ecco quelle implementazioni:

Implementazione 1:

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

Implementazione 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(''); } 

Attuazione 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(''); } 

Attuazione 4:

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

Implementazione 5:

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

Attuazione 6:

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

Attuazione 7:

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

Implementazione 8:

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

Implementazione 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(''); } 

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

In primo luogo, utilizzare Array.from() per trasformare una stringa in una matrice, quindi Array.prototype.reverse() per invertire la matrice e quindi Array.prototype.join() per ripristinare una stringa.

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

In ECMAScript 6, è ansible invertire una stringa ancora più velocemente senza utilizzare il metodo split .split('') , con l’ operatore di spread in questo modo:

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

Sembra che io abbia 3 anni di ritardo alla festa …

Purtroppo non è ansible, come è stato sottolineato. Vedi Le stringhe JavaScript sono immutabili? Ho bisogno di un “costruttore di stringhe” in JavaScript?

La prossima cosa migliore che puoi fare è creare una “vista” o “wrapper”, che prende una stringa e reimplementa qualsiasi parte dell’API di stringa che stai usando, ma fingendo che la stringa sia invertita. Per esempio:

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

Il kicker – il seguente viene fatto sul posto da pura matematica, visitando ogni personaggio solo una volta e solo se necessario:

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

Ciò produce risparmi significativi se applicato a una stringa molto grande, se si sta solo prendendo una fetta relativamente piccola di essa.

Se questo è valsa la pena (oltre al reverse-as-a-copy come nella maggior parte dei linguaggi di programmazione) dipende molto dal tuo caso d’uso e da quanto efficacemente reimplementi l’API della stringa. Ad esempio, se tutto ciò che si desidera è eseguire la manipolazione degli indici di stringa, o prendere piccole slice o substr s, ciò consentirà di risparmiare spazio e tempo. Se si prevede di stampare fette o sottostringhe rovesciate di grandi dimensioni, tuttavia, i risparmi potrebbero essere piccoli, persino peggiori rispetto a quando si è eseguita una copia completa. Anche la tua stringa “invertita” non avrà la string del tipo, anche se potresti essere in grado di simulare ciò con la prototipazione.

L’implementazione demo sopra descritta crea un nuovo object di tipo ReversedString. È prototipato e quindi abbastanza efficiente, con un lavoro quasi minimo e un sovraccarico di spazio minimo (le definizioni dei prototipi sono condivise). È un’implementazione pigra che coinvolge l’affettamento differito. Ogni volta che si esegue una funzione come .slice o .reversed , eseguirà la matematica dell’indice. Infine, quando si estraggono i dati (chiamando implicitamente .toString() o .charCodeAt(...) o qualcosa del genere), verranno applicati quelli in un modo “intelligente”, toccando il minor numero ansible di dati.

Nota: la precedente stringa API è un esempio e potrebbe non essere implementata perfettamente. Puoi anche utilizzare solo 1-2 funzioni di cui hai bisogno.

Durante un’intervista, mi è stato chiesto di invertire una stringa senza utilizzare variabili o metodi nativi. Questa è la mia implementazione preferita:

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

Questo è il modo più semplice che penso

 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 🍺')); 
 var str = 'sample string'; [].map.call(str, function(x) { return x; }).reverse().join(''); 

O

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

// Output: “gnirts elpmas”

So che questa è una vecchia domanda a cui è stata data una risposta soddisfacente, ma per il mio stesso divertimento ho scritto la seguente funzione inversa e ho pensato di condividerla nel caso in cui fosse utile per chiunque altro. Gestisce sia le coppie surrogate che i segni combinati:

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

Tutti gli oggetti di scena di Mathias, Punycode e vari altri riferimenti per insegnarmi le complessità della codifica dei caratteri in JavaScript.

In ES6, hai ancora un’opzione

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

La vera risposta è: non è ansible invertire la posizione, ma è ansible creare una nuova stringa che è il contrario.

Proprio come esercizio per giocare con la ricorsione: a volte quando si va a un colloquio, l’intervistatore potrebbe chiederti come farlo ricorrendo alla ricorsione, e penso che la “risposta preferita” potrebbe essere “Preferirei non farlo in ricorsione poiché può facilmente causare un overflow dello stack “(poiché è O(n) anziché O(log n) . Se è O(log n) , è piuttosto difficile ottenere un overflow dello stack: 4 miliardi di elementi potrebbero essere gestiti da un livello di stack di 32, come 2 ** 32 è 4294967296. Ma se è O(n) , allora può facilmente ottenere un overflow dello stack.

A volte l’intervistatore ti chiederà ancora “proprio come un esercizio, perché non lo scrivi ancora usando la ricorsione?” Ed eccolo qui:

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

prova:

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

produzione:

 999elppa899elppa...2elppa1elppa0elppa 

Per provare a ottenere un overflow dello stack, ho cambiato da 1000 a 10000 in Google Chrome e ha riportato:

 RangeError: Maximum call stack size exceeded 

Le stringhe sono immutabili, ma è ansible creare facilmente una copia inversa con il seguente codice:

 function reverseString(str) { var strArray = str.split(""); strArray.reverse(); var strReverse = strArray.join(""); return strReverse; } reverseString("hello"); 
 //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 
 function reverseString(string) { var reversedString = ""; var stringLength = string.length - 1; for (var i = stringLength; i >= 0; i--) { reversedString += string[i]; } return reversedString; } 

senza convertire string in 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 senza convertire i caratteri in punti codice;

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

Penso che String.prototype.reverse sia un buon modo per risolvere questo problema; il codice come sotto;

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

Usando le funzioni dell’array,

 String.prototype.reverse = function(){ return [].reduceRight.call(this, function(last, secLast){return last + secLast}); } 
 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=0;z--){ finalString = finalString +' '+ chunk[z]; console.log(finalString); } return true; } reverse(str); 

Il mio tentativo originale …

 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

Tenerlo ASCIUTTO e semplice sciocco !!

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

OK, abbastanza semplice, puoi creare una funzione con un semplice ciclo per fare la stringa inversa per te senza usare reverse() , charAt() ecc in questo modo:

Ad esempio hai questa stringa:

 var name = "StackOverflow"; 

Crea una funzione come questa, la chiamo 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 puoi chiamarlo come:

 reverseString(name); 

E il risultato sarà:

 "wolfrevOkcatS" 

Se non si desidera utilizzare alcuna funzione incorporata. Prova questo

  var string = 'abcdefg'; var newstring = ''; for(let i = 0; i < string.length; i++){ newstring = string[i] += newstring } console.log(newstring) 

Ci sono diversi modi per farlo, puoi controllare quanto segue,

1. Ciclo tradizionale per (incrementale):

 function reverseString(str){ let stringRev =""; for(let i= 0; i 

Un’altra variante (funziona con IE?):

 String.prototype.reverse = function() { for (i=1,s=""; i<=this.length; s+=this.substr(-i++,1)) {} return s; } 

MODIFICARE:

Questo è senza l'uso di funzioni built-in:

 String.prototype.reverse = function() { for (i=this[-1],s=""; i>=0; s+=this[i--]) {} return s; } 

Nota: questo [-1] contiene una lunghezza della stringa.

Tuttavia non è ansible invertire la stringa, poiché l'assegnazione ai singoli elementi dell'array non funziona con l'object String (protetto?). Cioè puoi fare assegnamenti, ma la stringa risultante non cambia.

 var str = "IAMA JavaScript Developer"; var a=str.split(''), b = a.length; for (var i=0; i 
 function reverse_string(string) { var string; var len = string.length; var stringExp = string.split(''); var i; for (i = len-1; i >=0;i--) { var result = document.write(stringExp[i]); } return result; } reverse_string("This is a reversed string"); 

// output: gnirts desrever a si siT

 function reverse(str){ var s = ""; for (var i = str.length - 1; i >= 0; i--){ s += str[i]; } return s; }; reverse("your string comes here")