javascript - Bir stringi yerinde nasıl ters çevirirsiniz?


JavaScript'te bir dize bir fonksiyona return ifadesi ile geçirildiğinde ve yerinde ters çevirmek istediğinizde, yerleşik fonksiyonları (.reverse(), .charAt() vb.) kullanmadan bunu nasıl yaparsınız?

Cevap #1

Basit ASCII karakterleriyle uğraştığınız sürece ve yerleşik fonksiyonları kullanmaktan memnunsanız, bu işe yarayacaktır:

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

UTF-16 veya diğer çok baytlı karakterleri destekleyen bir çözüme ihtiyacınız varsa, bu işlevin geçersiz unicode dizeleri vereceğini veya garip görünen geçerli dizeler üretebileceğini unutmayın. Bunun yerine bu cevabı göz önünde bulundurmak isteyebilirsiniz.

Dizi genişletme operatörü Unicode farkındadır:

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

MDN'de açıklandığı gibi, split() kullanarak başka bir Unicode farkında çözüm, ayırıcı olarak u (Unicode) bayrağı ayarlanmış bir düzenli ifade kullanmaktır.

function reverse(s){
    return s.split(/(?:)/u).reverse().join("");
}

Cevap #2

Aşağıdaki teknik (veya benzeri) JavaScript'te bir dizgeyi tersine çevirmek için yaygın olarak kullanılır:

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

Aslında, şimdiye kadar verilen tüm cevaplar bu kalıbın bir varyasyonudur. Ancak, bu çözümle ilgili bazı sorunlar vardır. Örneğin:

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

Bunun neden olduğunu merak ediyorsanız, JavaScript’in dahili karakter kodlaması hakkında bilgi edinin. (Kısaca: 𝌆 bir astral semboldür ve JavaScript bunu iki ayrı kod birimi olarak gösterir.)

Ama dahası var:

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

Dize tersine çevirme uygulamalarını test etmek için iyi bir dize şudur:

'foo 𝌆 bar mañana mañana'

Neden? Çünkü bir astral sembol (𝌆) (JavaScript'te vekil çiftlerle temsil edilir) ve bir birleştirme işareti (son mañana'daki ñ aslında iki sembolden oluşur: U+006E LATİN KÜÇÜK HARF N ve U+0303 BİRLEŞEN TILDE) içerir.

Yerini alıcı çiftlerin göründüğü sıra tersine çevrilemez, aksi takdirde astral sembol ‘ters çevrilmiş’ stringde artık görünmez. İşte bu yüzden önceki örnekteki çıktıda o �� işaretlerini gördünüz.

Birleştirme işaretleri her zaman önceki sembole uygulanır, bu nedenle hem temel simgeyi (U+006E LATİN KÜÇÜK HARF N) hem de birleştirme işaretini (U+0303 BİRLEŞTİRME TILDE) bir bütün olarak ele almanız gerekir. Sıralarının tersine çevrilmesi, birleştirme işaretinin dizideki başka bir sembolle eşleşmesine neden olacaktır. Örnek çıktının ñ yerine ñ olarak gösterilmesinin nedeni budur.

Umarım bu, şimdiye kadar gönderilen tüm cevapların neden yanlış olduğunu açıklar.

İlk sorunuza cevap vermek gerekirse — JavaScript'te bir dizgeyi [doğru bir şekilde] nasıl tersine çevirebilirsiniz —, Unicode farkındalıklı dizge tersine çevirme yeteneğine sahip küçük bir JavaScript kütüphanesi yazdım. Az önce bahsettiğim hiçbir sorunu yok. Kütüphanenin adı Esrever; kodu GitHub'da bulunuyor ve hemen her JavaScript ortamında çalışıyor. Ayrıca bir terminal/komut satırı aracı ile birlikte geliyor, böylece isterseniz dizgeleri terminalinizden kolayca ters çevirebilirsiniz.

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

“Yerinde” kısmı için diğer cevaplara bakın.

Cevap #3

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

veya

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

Cevap #4

Bir diziyi tersine çevirmenin ayrıntılı analizi ve on farklı yolu ile bunların performans detayları.

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

Bu uygulamaların performansı:

Tarayıcı başına en iyi performans gösteren uygulama(lar)

  • Chrome 15 - Uygulamalar 1 ve 6
  • Firefox 7 - Uygulama 6
  • IE 9 - Uygulama 4
  • Opera 12 - Uygulama 9

İşte o uygulamalar:

Uygulama 1:

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

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

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

Uygulama 4:

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

Uygulama 5:

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

Uygulama 6:

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

Uygulama 7:

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

Uygulama 8:

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

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

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

Uygulama 11

var reverser  = function(str){
let string = str.split('');

    for(i=0;i<string.length;i++){
        debugger;
        string.splice(i,0,string.pop());
    
    } 
    console.log(string.join())
}
reverser('abcdef')

Cevap #5

Bütün "bir string'i yerinde ters çevirme" sorusu, C programcılarının ve onların mülakat yaptığı kişilerin (belki de intikam için?) sorduğu eski bir mülakat sorusudur. Ne yazık ki, artık çalışmayan kısmı "Yerinde" kısmıdır çünkü neredeyse tüm yönetilen dillerde (JS, C# vb.) kullanılan stringler değiştirilemezdir, bu da hiçbir yeni bellek tahsisi yapmadan bir string'i taşıma fikrini tamamen bozar.

Yukarıdaki çözümler gerçekten bir diziyi tersine çevirse de, bunu daha fazla bellek tahsis etmeden yapmazlar ve dolayısıyla şartları karşılamazlar. Diziyi tahsis edildiği haliyle doğrudan erişebilmeniz ve yerinde tersine çevirebilmek için orijinal bellek konumunu manipüle edebilmeniz gerekir.

Kişisel olarak, bu tür mülakat sorularını gerçekten nefret ediyorum, ama ne yazık ki, önümüzdeki yıllarda onları görmeye devam edeceğimizden eminim.

Cevap #6

Önce bir stringi diziye çevirmek için Array.from() kullanın, sonra diziyi tersine çevirmek için Array.prototype.reverse() kullanın ve ardından tekrar string yapmak için Array.prototype.join() kullanın.

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

Cevap #7

ECMAScript 6'da, .split('') split yöntemini kullanmadan, yayma operatörü ile bir stringi daha hızlı ters çevirebilirsiniz, şöyle ki:

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

Cevap #8

Görünüşe göre partiye 3 yıl geç kaldım...

Ne yazık ki, belirtildiği gibi bunu yapamazsınız. Bkz. JavaScript dizeleri değiştirilemez mi? JavaScript'te bir "string builder"a ihtiyacım var mı?

Yapabileceğiniz bir sonraki en iyi şey, bir string alan ve kullandığınız string API'sinin herhangi bir bölümünü yeniden uygulayan, ancak string ters çevrilmiş gibi davranan bir "görünüm" veya "sarmalayıcı" oluşturmaktır. Örneğin:

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"

Asıl sürpriz -- aşağıdaki işlem saf matematikle yerinde yapılır, her karakteri yalnızca bir kez ziyaret ederek ve yalnızca gerekirse:

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

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

Bu, yalnızca ondan nispeten küçük bir dilim alıyorsanız, çok büyük bir dizeye uygulandığında önemli tasarruf sağlar.

Bunun buna değip değmeyeceği (çoğu programlama dilinde olduğu gibi kopya üzerinden ters çevirme yerine) büyük ölçüde kullanım durumunuza ve string API'sini ne kadar verimli şekilde yeniden uyguladığınıza bağlıdır. Örneğin, tek yapmak istediğiniz şey string indeks manipülasyonu yapmak veya küçük slice'lar veya substr'lar almaksa, bu size yer ve zaman kazandırır. Ancak büyük ters çevrilmiş dilimleri veya alt dizeleri yazdırmayı planlıyorsanız, tasarruf gerçekten küçük olabilir, hatta tam bir kopya yapmaktan daha kötü bile olabilir. "Ters çevrilmiş" stringiniz ayrıca string türünde olmayacaktır, ancak bunu prototipleme ile taklit edebilmeniz mümkün olabilir.

Yukarıdaki demo uygulaması, ReversedString türünde yeni bir nesne oluşturur. Prototip tabanlıdır ve bu nedenle neredeyse minimal iş ve minimal alan maliyeti ile oldukça verimlidir (prototip tanımları paylaşılır). Gecikmeli dilimleme içeren tembel bir uygulamadır. .slice veya .reversed gibi bir fonksiyon çalıştırdığınızda, indeks matematiği uygulayacaktır. Son olarak, veriyi çıkardığınızda (örtük olarak .toString() veya .charCodeAt(...) veya benzer bir şeyi çağırdığınızda), bunu "akıllı" bir şekilde, mümkün olan en az veri üzerinde uygulayacaktır.

Not: Yukarıdaki string API'si bir örnektir ve mükemmel bir şekilde uygulanmamış olabilir. Ayrıca sadece ihtiyacınız olan 1-2 fonksiyonu da kullanabilirsiniz.

Cevap #9

Spread sözdizimi kullanarak okunabilir yol:

const reverseString = str => [...str].reverse().join('');

console.log(reverseString('ABC'));

Cevap #10

JavaScript'te bir dizgiyi tersine çevirmenin birçok yolu vardır. Ben tercih ettiğim üç yolu not ediyorum.

Yöntem 1: reverse fonksiyonunu kullanmak:

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

Yöntem 2: Karakterler arasında döngü:

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

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

  return reversed;
}

Yöntem 3: reduce fonksiyonunu kullanmak:

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

Umarım bu işe yarar :)

Cevap #11

Bunu yapmanın birden fazla yolu vardır, aşağıdakileri kontrol edebilirsiniz,

1. Geleneksel for döngüsü (arttırma):

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

2. Geleneksel for döngüsü (azaltan):

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. for-of döngüsü kullanımı

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

4. forEach/ yüksek seviyeli dizi yöntemi kullanımı:

function reverseString(str){

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

5. ES6 standardı:

function reverseString(str){

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

6. En son yol:

function reverseString(str){

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

alert(reverseString("Learning JavaScript"));

7. Sonucu ayrıca aşağıdakileri kullanarak da alabilirsiniz,

function reverseString(str){

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

Cevap #12

Bir röportaj sırasında, herhangi bir değişken veya yerleşik yöntem kullanmadan bir dizgeyi ters çevirmem istendi. Bu benim en sevdiğim uygulamam:

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

İlgili makaleler