599 Stimmen

Wie kehrt man in JavaScript eine Zeichenkette an Ort und Stelle um?

Wie kehrt man eine Zeichenkette in JavaScript an Ort und Stelle um, wenn sie an eine Funktion mit einer Rückgabeanweisung übergeben wird, ohne integrierte Funktionen zu verwenden ( .reverse() , .charAt() usw.)?

0 Stimmen

Sie dürfen also nicht .charAt() verwenden, um die Zeichen der Zeichenkette zu erhalten?

192 Stimmen

Das können Sie nicht. JavaScript-Zeichenfolgen sind unveränderlich, was bedeutet, dass der Speicher, der ihnen zugewiesen ist, nicht beschrieben werden kann, was echte "In-Place"-Umkehrungen unmöglich macht.

3 Stimmen

Re: crescentfresh's Kommentar siehe stackoverflow.com/questions/51185/

6voto

jitendra rajput Punkte 586

Wenn Sie keine der eingebauten Funktionen verwenden möchten. Versuchen Sie dies

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

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

console.log(newstring);

6voto

Nick Parsons Punkte 37650

Eine neue Option ist die Verwendung von Intl. Segmentierer die es Ihnen ermöglicht, die visuellen Grapheme (d. h. vom Benutzer wahrgenommene Zeicheneinheiten wie Emojis, Buchstaben usw.) aufzuteilen. Intl.Segmenter ist derzeit ein Vorschlag für Stufe 4 und es gibt eine Polyfill zur Verfügung, wenn Sie es verwenden möchten. Es hat derzeit eine begrenzte Browserunterstützung, über die Sie weitere Informationen finden können aquí .

So wird die reverse() Methode aussehen kann, wenn Sie die Intl.Segmenter :

const reverse = str => {
  const segmenter = new Intl.Segmenter("en", {granularity: 'grapheme'});
  const segitr = segmenter.segment(str);
  const segarr = Array.from(segitr, ({segment}) => segment).reverse();
  return segarr.join('');
}

console.log(reverse('foo  bar mañana manana')); // ananam anañam rab  oof
console.log(reverse('This  emoji is happy')); // yppah si ijome  sihT
console.log(reverse('Text surrogate pair  composite pair moo varient selector  & ZWJ ')); //  JWZ &  rotceles tneirav oom riap etisopmoc  riap etagorrus txeT

Die obigen Ausführungen schaffen eine segmenter um Zeichenketten anhand ihrer visuellen Grapheme zu segmentieren/aufzuteilen. Aufruf von .segment() über die segmenter mit der Zeichenkette input gibt dann einen Iterator zurück, der Objekte der Form {segment, index, input, isWordLike} . Die segment Schlüssel dieses Objekts enthält das Zeichenkettensegment (d. h. das einzelne Graphem). Um den Iterator in ein Array umzuwandeln, verwenden wir Array.from() auf den Iterator und extrahieren die segmentierten Grapheme, die mit .reverse() . Zum Schluss fügen wir das Array wieder zu einer Zeichenkette zusammen, indem wir .join()


Es gibt auch eine andere Option, die Sie ausprobieren können, die eine bessere Browserunterstützung als Intl.Segmenter bietet, aber nicht so kugelsicher ist:

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

Dies hilft bei Zeichen, die aus mehreren Codepunkten und Codeeinheiten bestehen. Wie bereits in anderen Antworten erwähnt, gibt es Probleme mit der Beibehaltung der Reihenfolge von zusammengesetzten und Surrogatpaaren in Zeichenketten wie 'foo bar mañana manana' . Hier ist ein Surrogatpaar, das aus zwei Codeeinheiten besteht, und die letzte n ist ein zusammengesetztes Paar, das aus zwei Unicode-Zeichen besteht, um ein Graphem zu bilden ( n + \= n ).

Um jedes Zeichen umzukehren, können Sie die .reverse() Methode, die Teil des Array-Prototyps ist. Als .reverse() auf ein Array angewendet wird, muss zunächst die Zeichenkette in ein Array von Zeichen umgewandelt werden. Typischerweise, .split('') wird für diese Aufgabe verwendet, allerdings werden dabei Surrogatpaare aufgespalten, die aus mehreren Codeeinheiten bestehen (wie bereits in frühere Antworten ) :

>> ''.split('')
>> `["", ""]`

Wenn Sie stattdessen die Funktion String.prototype 's Symbol.Iterator Methode können Sie Ihre Surrogatpaare in Ihrem Array beibehalten, da diese über die Codepunkte und nicht über die Codeeinheiten Ihrer Zeichenfolge iteriert:

>> [...'']
>> [""]

Als nächstes müssen alle zusammengesetzten Zeichen in der Zeichenfolge behandelt werden. Zeichen, die aus zwei oder mehr Codepunkten bestehen, werden auch bei der Iteration aufgespalten:

>> [...'o']   
>> ["o", ""]

Das obige Beispiel trennt das Basiszeichen (o) von der Diaresis, was nicht erwünscht ist. Der Grund dafür ist o ist eine dekomponierte Version des Zeichens, die aus mehreren Codepunkten besteht. Um damit umzugehen, können Sie eine in ES6 eingeführte String-Methode verwenden, die als String.prototype.normalize() . Diese Methode kann mehrere Code-Punkte in ihre zusammengesetzte kanonische Form indem wir "NFC" als Argument verwenden. Dies erlaubt uns, das zerlegte Zeichen umzuwandeln o (o + Diaerese kombinieren ) in seine vorkomponierte Form ö ( lateinischer Kleinbuchstabe o mit Diaeresis ), die nur aus einem Codepunkt besteht. Aufruf von .normalize() con "NFC" versucht daher, mehrere Codepunkte durch einzelne Codepunkte zu ersetzen soweit möglich . Dadurch können Grapheme, die aus zwei Codepunkten bestehen, mit einem Codepunkt dargestellt werden.

>> [...'o'.normalize('NFC')]   
>> ["ö"]

Als normalize('NFC') ein Zeichen erzeugt, kann es unter anderen Zeichen sicher umgedreht werden. Wenn man sowohl die Spreizsyntax als auch die Normalisierung kombiniert, kann man erfolgreich Zeichenketten umkehren, z. B:

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

console.log(reverse('foo  bar mañana manana'));
console.log(reverse('This  emoji is happy'));

Es gibt ein paar Fälle, in denen die obige Normalisierung+Iteration fehlschlägt. Zum Beispiel, das Zeichen (schweres schwarzes Herz ) besteht aus zwei Codepunkten. Der erste ist das Herz und der zweite ist der Variationsselektor-16 (U+FE0F), das dazu dient, eine Glyphenvariante für das vorhergehende Zeichen zu definieren. Auch andere Zeichen können ähnliche Probleme verursachen.

Ein weiterer Punkt, auf den man achten sollte, ist ZWJ (Zero-width joiner) Zeichen, die in einigen Schriften zu finden sind, einschließlich Emoji. Das Emoji besteht zum Beispiel aus den Emoji Mann, Frau und Junge, die jeweils durch ein ZWJ getrennt sind. Die obige Normalisierungs- und Iterationsmethode berücksichtigt dies ebenfalls nicht.

Infolgedessen ist die Verwendung von Intl.Segmenter ist die bessere Wahl gegenüber diesen beiden Ansätzen. Derzeit hat Chrome auch seine eigene spezifische Segmentierungs-API, die als Intl.v8BreakIterator . Diese Segmentierungs-API ist nicht Standard und etwas, das Chrome einfach nur implementiert. Es kann sich also ändern und funktioniert in den meisten Browsern nicht, daher wird seine Verwendung nicht empfohlen. Wenn Sie jedoch neugierig sind, können Sie es so machen:

const reverse = str => {
  const iterator = Intl.v8BreakIterator(['en'], {type: 'character'});
  iterator.adoptText(str);
  const arr = [];
  let pos = iterator.first();
  while (pos !== -1) {
    const current = iterator.current();
    const nextPos = iterator.next();
    if (nextPos === -1) break;
    const slice = str.slice(current, nextPos);
    arr.unshift(slice);
  }
  return arr.join("");
}

console.log(reverse('foo  bar mañana manana')); // ananam anañam rab  oof
console.log(reverse('This  emoji is happy')); // yppah si ijome  sihT
console.log(reverse('Text surrogate pair  composite pair moo varient selector  & ZWJ ')); //  JWZ &  rotceles tneirav oom riap etisopmoc  riap etagorrus txeT

5voto

Giacomo Casadei Punkte 1098

Sie können eine string aber Sie können dies verwenden:

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

var s = "ABCD";
s = s.reverse();
console.log(s);

5voto

Scott Gartner Punkte 804

Ich weiß, dass dies eine alte Frage ist, die bereits gut beantwortet wurde, aber zu meinem eigenen Vergnügen habe ich die folgende Umkehrfunktion geschrieben und dachte, ich würde sie mit anderen teilen, falls sie für jemand anderen nützlich ist. Sie verarbeitet sowohl Surrogatpaare als auch Kombinationszeichen:

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

Alle Requisiten zu Mathias, Punycode, und verschiedene andere Referenzen für die Schule mich auf die Komplexität der Zeichenkodierung in JavaScript.

5voto

Kamil Kiełczewski Punkte 69048

Sie können nicht, weil JS-Strings unveränderlich sind. Kurze Nicht-in-Place-Lösung

[...str].reverse().join``

let str = "Hello World!";
let r = [...str].reverse().join``;
console.log(r);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X