คุณจะย้อนกลับสตริงในสถานที่ใน JavaScript ได้อย่างไร


435

คุณจะทำอย่างไรกลับสตริงในสถานที่ (หรือในสถานที่) ใน JavaScript เมื่อมีการส่งผ่านไปยังฟังก์ชั่นที่มีคำสั่งกลับโดยไม่ต้องใช้ฟังก์ชั่น ( .reverse(), .charAt()ฯลฯ )?


ดังนั้นคุณไม่ได้รับอนุญาตให้ใช้. charAt () เพื่อรับตัวอักษรของสตริง?
Irwin

155
คุณทำไม่ได้ สตริง JavaScript นั้นไม่สามารถเปลี่ยนแปลงได้ซึ่งหมายถึงหน่วยความจำที่จัดสรรให้แต่ละตัวไม่สามารถเขียนได้
Crescent Fresh

2
Re: ความคิดเห็นของ crescentfresh ดูstackoverflow.com/questions/51185/…
baudtack

1
@crescentfresh คุณควรโพสต์สิ่งนั้นเป็นคำตอบใหม่
baudtack

คำตอบ:


736

ตราบใดที่คุณจัดการกับอักขระ ASCII แบบง่ายและคุณยินดีที่จะใช้ฟังก์ชั่นในตัวสิ่งนี้จะใช้ได้:

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

หากคุณต้องการโซลูชันที่รองรับ UTF-16 หรืออักขระหลายไบต์อื่น ๆ โปรดทราบว่าฟังก์ชั่นนี้จะให้สตริง Unicode ที่ไม่ถูกต้องหรือสตริงที่ถูกต้องที่ดูตลก คุณอาจต้องการที่จะต้องพิจารณาคำตอบนี้แทน

[... s] ทราบ Unicode การแก้ไขเพียงเล็กน้อยให้: -

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

44
สิ่งนี้หักสำหรับสตริง UTF-16 ที่มีคู่ตัวแทนตัวแทนนั่นคืออักขระที่อยู่นอกระนาบหลายภาษาพื้นฐาน นอกจากนี้ยังจะให้ผลลัพธ์ที่ตลกสำหรับสตริงที่มีตัวอักษรรวมกันเช่นไดอะซิสที่อาจปรากฏในตัวอักษรต่อไป ปัญหาแรกจะนำไปสู่สตริง unicode ที่ไม่ถูกต้องสตริงที่สองเป็นสตริงที่ถูกต้องซึ่งดูตลก
Martin Probst

2
@Richeve Bebedor "ทั้งหมดโดยไม่ต้องใช้ฟังก์ชั่นในตัว?. กลับ ()" นี่จะไม่ใช่วิธีการแก้ปัญหาที่ยอมรับได้เพราะมันไม่เหมาะกับขอบเขตของคำถามแม้จะเป็นทางออกที่ทำงานได้จริงในการย้อนกลับสตริงใน JS
David Starkey

1
@DavidStarkey: ใช่มองย้อนกลับไปเกือบสี่ปีต่อมามันยากที่จะดูว่าฉันพลาดจุดคำถามอย่างถี่ถ้วน ดูเหมือนว่าฉันควรจะรอสองนาทีและแสดงความคิดเห็นของ crescentfresh upvoted ในโพสต์ต้นฉบับ!
belacqua

14
@MartinProbst คำตอบของฉันมอบวิธีการแก้ปัญหา Unicode ที่ตระหนักถึงปัญหาที่เกี่ยวข้องกับคู่ตัวแทนและการรวมเครื่องหมายอย่างถูกต้อง: stackoverflow.com/a/16776380/96656
Mathias Bynens

1
สำหรับ UTF-16 return [...s].reverse().join("");อาจใช้งานได้
user4642212

411

เทคนิคต่อไปนี้ (หรือคล้ายกัน) มักใช้เพื่อย้อนกลับสตริงใน JavaScript:

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

อันที่จริงคำตอบทั้งหมดที่โพสต์จนถึงตอนนี้เป็นรูปแบบของรูปแบบนี้ อย่างไรก็ตามมีปัญหาบางอย่างกับวิธีนี้ ตัวอย่างเช่น:

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

หากคุณกำลังสงสัยว่าทำไมนี้เกิดขึ้นอ่านข้อมูลเกี่ยวกับการเข้ารหัสอักขระภายในของ JavaScript (TL; DR: 𝌆เป็นสัญลักษณ์คล้ายดาวและ JavaScript แสดงเป็นหน่วยรหัสแยกกันสองหน่วย)

แต่ยังมีอีก:

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

สตริงที่ดีในการทดสอบการใช้งานสตริงกลับเป็นดังต่อไปนี้ :

'foo 𝌆 bar mañana mañana'

ทำไม? เพราะมันมีสัญลักษณ์คล้ายดาว ( 𝌆) (ซึ่งแสดงโดยคู่ตัวแทนใน JavaScript ) และเครื่องหมายรวม ( ในสุดท้ายที่mañanaจริงประกอบด้วยสองสัญลักษณ์: U + 006E LATIN ตัวอักษรขนาดเล็ก N และ U + 0303 COMBINING TILDE)

ลำดับที่คู่ตัวแทนแทนที่ไม่สามารถย้อนกลับได้มิฉะนั้นสัญลักษณ์ดาวจะไม่ปรากฏขึ้นอีกต่อไปในสตริง 'สลับกลับ' นั่นเป็นเหตุผลที่คุณเห็น��เครื่องหมายเหล่านั้นในผลลัพธ์สำหรับตัวอย่างก่อนหน้า

เครื่องหมายรวมจะถูกนำไปใช้กับสัญลักษณ์ก่อนหน้าเสมอดังนั้นคุณต้องปฏิบัติต่อทั้งสัญลักษณ์หลัก (U + 006E LATIN LETTER เล็ก L ตัวอักษร N) เป็นเครื่องหมายรวม (U + 0303 COMBINING TILDE) โดยรวม การกลับคำสั่งซื้อจะทำให้เครื่องหมายรวมกันจับคู่กับสัญลักษณ์อื่นในสตริง นั่นเป็นเหตุผลที่การส่งออกเช่นมีแทนñ

หวังว่านี้จะอธิบายว่าทำไมคำตอบทั้งหมดที่โพสต์เพื่อให้ห่างไกลมีความผิด


เพื่อตอบคำถามเริ่มต้นของคุณ - วิธี [ย้อนกลับอย่างถูกต้อง] สตริงใน JavaScript - ฉันได้เขียนไลบรารี JavaScript ขนาดเล็กที่สามารถย้อนกลับสตริง Unicode ที่ทราบได้ ไม่มีปัญหาใด ๆ ที่ฉันเพิ่งพูดถึง ห้องสมุดที่เรียกว่าEsrever ; รหัสของมันอยู่บน GitHub และทำงานในสภาพแวดล้อม JavaScript ใด ๆ มันมาพร้อมกับยูทิลิตี้เชลล์ / ไบนารีดังนั้นคุณสามารถย้อนกลับสตริงจากเทอร์มินัลของคุณได้อย่างง่ายดายหากคุณต้องการ

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

สำหรับส่วน "ในสถานที่" ให้ดูคำตอบอื่น ๆ


65
คุณควรรวมส่วนหลักของรหัส Esrever ไว้ในคำตอบของคุณ
r0estir0bbe

1
@Meglio ด้วยวิธีการเฉพาะนั้นใช่
Mathias Bynens

8
ปัญหานอกหลักสูตรคือ "ย้อนกลับสตริง" ฟังดูไม่น่าสงสัย แต่ก็ไม่ได้อยู่ในปัญหาที่กล่าวถึงที่นี่ การย้อนกลับสตริงที่ส่งคืนสตริงที่เมื่อพิมพ์จะแสดงกลุ่มกราฟในสตริงในลำดับย้อนกลับหรือไม่ ในอีกด้านหนึ่งนั่นฟังดูเป็นไปได้ ทำไมคุณถึงอยากทำเช่นนั้น คำจำกัดความนี้ขึ้นอยู่กับการพิมพ์และการพิมพ์สตริงที่ตรงกันข้ามนั้นไม่ค่อยมีประโยชน์ ในฐานะที่เป็นส่วนหนึ่งของอัลกอริทึมความต้องการของคุณอาจแตกต่างกันโดยสิ้นเชิง
Martijn

19
ขณะนี้ไม่ได้ดีงานของการอธิบายปัญหาที่เกิดขึ้นจริงคำตอบคือในปราสาทอีก ดังที่ @ r0estir0bbe พูดเมื่อหนึ่งปีก่อนรหัสที่เกี่ยวข้องควรอยู่ในคำตอบไม่ใช่เชื่อมโยง
TJ Crowder

4
"หวังว่านี่จะอธิบายว่าทำไมคำตอบทั้งหมดที่โพสต์ไปนั้นผิด" - การยืนยันนี้เป็น IMO ที่มีพลังมากเกินไป กรณีใช้งานจำนวนมากไม่ต้องการการสนับสนุน UTF-16 (ตัวอย่างง่าย ๆ การทำงานกับส่วนประกอบ / พารามิเตอร์ URL และ URL) การแก้ปัญหาไม่ใช่ "ผิด" เพียงเพราะไม่ได้จัดการกับสถานการณ์ที่ไม่จำเป็น โดยเฉพาะอย่างยิ่งคำตอบที่ได้รับคะแนนสูงสุดประกาศอย่างชัดเจนว่าใช้ได้กับอักขระ ASCII เท่านั้นจึงไม่ผิดแม้แต่น้อย
aroth

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

หรือ

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

ฉันเห็นด้วยกับต้นแบบ String แน่นอน
Jeff Meatball Yang

3
การต่อสตริงมีราคาแพง ดีกว่าที่จะสร้างอาร์เรย์และเข้าร่วมหรือใช้ concat ()
Bjorn

2
# 1 ดีที่สุด # 2 อาจช้าอย่างน่ากลัว
adamJLev

9
อย่างไรก็ตามโซลูชันไม่ทำงานเมื่อมีอักขระผสม Unicode อยู่
Eric Grange

2
@JuanMendes ฉันทิ้งความคิดเห็นไว้ในปี 2009 สิ่งต่าง ๆ มีการเปลี่ยนแปลงใน 4 ปี : P
Bjorn

63

การวิเคราะห์โดยละเอียดและสิบวิธีในการย้อนกลับสตริงและรายละเอียดประสิทธิภาพ

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

Perfomance ของการใช้งานเหล่านี้:

การใช้งานที่มีประสิทธิภาพสูงสุดต่อเบราว์เซอร์

  • Chrome 15 - การดำเนินการ 1 และ 6
  • Firefox 7 - การใช้งาน 6
  • IE 9 - การติดตั้งใช้งาน 4
  • Opera 12 - การใช้งาน 9

นี่คือการใช้งานเหล่านั้น:

การใช้งาน 1:

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

การใช้งาน 2:

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

การใช้งาน 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('');
}

การใช้งาน 4:

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

การใช้งาน 5:

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

การใช้งาน 6:

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

การใช้งาน 7:

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

การใช้งาน 8:

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

การใช้งาน 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('');
    }

การใช้งาน 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

ทั้งหมด "ย้อนกลับสตริงในสถานที่" เป็นคำถามสัมภาษณ์โบราณ C โปรแกรมเมอร์และคนที่ถูกสัมภาษณ์โดยพวกเขา (เพื่อแก้แค้นอาจ?) จะถาม น่าเสียดายที่มันเป็นส่วน "In Place" ที่ไม่สามารถใช้งานได้อีกต่อไปเพราะสตริงในภาษาที่ได้รับการจัดการ (JS, C #, ฯลฯ ) นั้นใช้สตริงที่ไม่เปลี่ยนรูปดังนั้นการเอาชนะความคิดทั้งหมดในการย้ายสตริงโดยไม่ต้องจัดสรรหน่วยความจำใหม่

ในขณะที่วิธีการแก้ปัญหาข้างต้นย้อนกลับสตริง แต่พวกเขาไม่ทำโดยไม่ต้องจัดสรรหน่วยความจำมากขึ้นและไม่ตอบสนองเงื่อนไข คุณต้องมีการเข้าถึงสตริงโดยตรงตามที่จัดสรรและสามารถจัดการตำแหน่งหน่วยความจำดั้งเดิมเพื่อให้สามารถย้อนกลับได้

โดยส่วนตัวแล้วฉันเกลียดการสัมภาษณ์ประเภทนี้จริง ๆ แต่น่าเศร้าฉันแน่ใจว่าเราจะเห็นพวกเขาต่อไปอีกหลายปี


7
อย่างน้อยฉันก็สามารถพูดได้ว่าฉันมีผู้สัมภาษณ์ซักพักหนึ่งหลังรู้สึกประทับใจเมื่อเขาถามฉันถึงวิธีการย้อนสตริง "ในสถานที่" ใน JS และฉันอธิบายว่าทำไมมันเป็นไปไม่ได้เนื่องจากสตริงใน JS ไม่เปลี่ยนรูป ฉันไม่รู้ว่านั่นคือคำตอบที่เขาคาดหวังหรือถ้าฉันสอนเขาเล็กน้อย ไม่ว่ามันจะเป็นไปได้ด้วยวิธีใด;)
Chev

1
บางทีเขาอาจหมายถึง "จัดการ" โดยตัวรวบรวมขยะอย่างน้อยนั่นคือสิ่งที่มักจะหมายถึงโดย "ภาษาที่ได้รับการจัดการ" หรือการปรากฏตัวของสภาพแวดล้อมของ Virtual Machine / Virtual Runtime? @torazaburo
AntonB

39

ก่อนอื่นให้ใช้Array.from()เพื่อเปลี่ยนสตริงให้เป็นอาร์เรย์จากนั้นจึงArray.prototype.reverse()ย้อนกลับอาร์เรย์แล้วArray.prototype.join()จึงกลับสตริง

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

มันมีค่าใช้จ่าย แต่นี่เป็นทางออกที่สง่างาม! ไม่มีการเขียนreverseลอจิกที่มีอยู่แล้ว
Gershom

2
@felixfbecker string.split('')ไม่ไม่ทำงาน ดูคำตอบนี้สำหรับคำอธิบายเพิ่มเติม
MichałPerłakowski

5
นี่ควรเป็นคำตอบที่ได้รับการยอมรับเพราะมันใช้ได้กับยูนิโค้ดด้วย เช่นจากตัวอย่างด้านบน:Array.from('foo 𝌆 bar mañana mañana').reverse().join('') == 'anãnam anañam rab 𝌆 oof'
Julian TF

3
@JulianTF ไม่แน่ชัด tilde หนึ่งตัวยังคงใช้กับ 'a' แทนที่จะเป็น 'n'
Roman Boiko

2
@RomanBoiko True แต่คุณสามารถทำให้มาตรฐานเป็นอันดับแรกได้ Array.from('foo 𝌆 bar mañana mañana'.normalize('NFC')).reverse().join('')จะกลายเป็น"anañam anañam rab 𝌆 oof"
นายลิสเตอร์

26

ใน ECMAScript 6 คุณสามารถย้อนกลับสตริงได้เร็วขึ้นโดยไม่ต้องใช้.split('')วิธีแยกโดยมีตัวดำเนินการกระจายดังนี้:

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

1
ES6 ยังอนุญาตให้คุณใช้ backticks สองตัว `` แทน('')

มีเหตุผลที่จะใช้สอง backticks ในกรณีนี้
วิก

1
คุณควรหลีกเลี่ยงสิ่งนี้ เขียนชัดเจนเพื่อคนส่วนใหญ่กว่าstring.split('') [...string]
AnnanFay

1
@AnnanFay .split('')มีปัญหากับตัวละครจากเครื่องบินเสริม (คู่ตัวแทน UTF-16) เพราะมันแยกจาก UTF-16 รหัสหน่วยมากกว่ารหัสจุด ผู้ดำเนินการแพร่กระจายและArray.from()(การตั้งค่าของฉัน) ไม่
เฉลย

@Inkling ฉันไม่ทราบว่าเป็นปัญหา ขอบคุณที่ชี้นำ ฉันยังคงอยากจะเขียนฟังก์ชั่นยูทิลิตี้เพื่อความชัดเจน
AnnanFay

19

ดูเหมือนว่าฉันจะไปงานเลี้ยง 3 ปี ...

น่าเสียดายที่คุณไม่สามารถอธิบายได้ ดูว่าสตริง JavaScript ไม่เปลี่ยนรูปหรือไม่ ฉันต้องการ "เครื่องมือสร้างสตริง" ใน JavaScript หรือไม่

สิ่งที่ดีที่สุดถัดไปที่คุณสามารถทำได้คือการสร้าง "มุมมอง" หรือ "เสื้อคลุม" ซึ่งใช้สตริงและ reimplements ส่วนใด ๆ ของสตริง API ที่คุณใช้ แต่ทำท่าว่าจะย้อนกลับ ตัวอย่างเช่น:

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

การสาธิต:

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

The kicker - สิ่งต่อไปนี้ทำโดยใช้คณิตศาสตร์บริสุทธิ์เข้าเยี่ยมชมตัวละครแต่ละตัวเพียงครั้งเดียวและในกรณีที่จำเป็นเท่านั้น:

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

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

สิ่งนี้ให้การประหยัดที่สำคัญหากนำไปใช้กับสตริงที่มีขนาดใหญ่มากหากคุณใช้เพียงส่วนที่ค่อนข้างเล็ก

ไม่ว่าจะเป็นสิ่งที่คุ้มค่า (มากกว่าการย้อนกลับเป็นสำเนาในภาษาการเขียนโปรแกรมส่วนใหญ่) ขึ้นอยู่กับกรณีการใช้งานของคุณและประสิทธิภาพในการปรับใช้สตริง API อีกครั้งอย่างมีประสิทธิภาพ ตัวอย่างเช่นถ้าทั้งหมดที่คุณต้องการคือการทำดัชนีการจัดการสตริงหรือใช้ขนาดเล็กsliceหรือsubstrs นี้จะช่วยให้คุณประหยัดพื้นที่และเวลา หากคุณวางแผนที่จะพิมพ์ชิ้นส่วนหรือวัสดุที่ตรงกันข้ามขนาดใหญ่การประหยัดอาจมีขนาดเล็กแน่นอนยิ่งแย่กว่าการทำสำเนาแบบเต็ม สตริง "กลับด้าน" ของคุณจะไม่มีประเภทstringเช่นกันแม้ว่าคุณอาจปลอมแปลงด้วยการสร้างต้นแบบ

การใช้งานการสาธิตด้านบนสร้างวัตถุใหม่ชนิด ReversedString มันเป็นต้นแบบและมีประสิทธิภาพค่อนข้างด้วยงานที่น้อยที่สุดและค่าใช้จ่ายในพื้นที่น้อยที่สุด (คำจำกัดความต้นแบบจะใช้ร่วมกัน) มันเป็นการใช้งานที่ขี้เกียจซึ่งเกี่ยวกับการแบ่งส่วนรอตัดบัญชี เมื่อใดก็ตามที่คุณทำหน้าที่เหมือน.sliceหรือ.reversedมันจะทำการคำนวณดัชนีทางคณิตศาสตร์ ในที่สุดเมื่อคุณดึงข้อมูล (โดยการโทรโดยปริยาย.toString()หรือ.charCodeAt(...)หรือบางอย่าง) มันจะใช้ข้อมูลเหล่านั้นในลักษณะ "ฉลาด" สัมผัสกับข้อมูลน้อยที่สุดเท่าที่จะเป็นไปได้

หมายเหตุ: API สตริงข้างต้นเป็นตัวอย่างและอาจไม่มีการใช้งานอย่างสมบูรณ์ คุณสามารถใช้ฟังก์ชั่น 1-2 อย่างที่คุณต้องการ


13

มีหลายวิธีที่คุณสามารถย้อนกลับสตริงใน JavaScript ฉันจดสามวิธีที่ฉันชอบ

วิธีที่ 1: การใช้ฟังก์ชั่นย้อนกลับ:

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

วิธีที่ 2: วนลูปผ่านตัวอักษร:

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

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

  return reversed;
}

วิธีที่ 3: การใช้ฟังก์ชั่นลด:

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

ฉันหวังว่านี่จะช่วยได้ :)


10

ในระหว่างการสัมภาษณ์ฉันถูกขอให้ย้อนกลับสตริงโดยไม่ต้องใช้ตัวแปรหรือวิธีการเนทีฟ นี่คือการใช้งานที่ชื่นชอบ:

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

สั้นง่าย แต่ช้าเหมือนนรก;)
ทอม

13
เป็นศูนย์วิธีพื้นเมือง? เกี่ยวกับsliceอะไร : - /
ใบไม้

1
การใช้การสอบถามซ้ำที่น่าสนใจ แดกดันว่ามันอยู่ในกองล้น stackoverflow.com/q/2805172/265877
Alex

@ อเล็กซ์คุณทำให้เป็นจุดที่ดี Array.prototype.reverse()ในบางกรณีผู้สัมภาษณ์จะถามคุณจะไม่ใช้
Daniel

10

มีหลายวิธีในการทำคุณสามารถตรวจสอบสิ่งต่อไปนี้

1. แบบดั้งเดิมสำหรับการวนซ้ำ (การเพิ่มขึ้น):

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

2. แบบดั้งเดิมสำหรับลูป (ลดค่า):

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 loop

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

4. การใช้วิธีอาร์เรย์ forEach / high order:

function reverseString(str){

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

5. มาตรฐาน ES6:

function reverseString(str){

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

6. วิธีล่าสุด:

function reverseString(str){

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

alert(reverseString("Learning JavaScript"));

7. คุณอาจได้รับผลลัพธ์โดยใช้สิ่งต่อไปนี้

function reverseString(str){

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



6

นี่เป็นวิธีที่ง่ายที่สุดที่ฉันคิด

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
มันดีที่คุณใส่อีโมจิไว้ในตัวอย่างของคุณ เพื่อให้เราเห็นได้อย่างรวดเร็วว่าสิ่งนี้ไม่สามารถใช้ได้กับอิโมจิและตัวอักษรยูนิโค้ดอื่น ๆ มากมาย
ÍhorMé

ศรัทธาในขณะที่คำตอบของคุณถูกต้องฉันไม่เห็นด้วยว่าเป็นวิธีที่ง่ายที่สุด คำตอบหลาย ๆ คำแรกใช้ประโยชน์จากArray.prototype.reverse()สิ่งนั้นเป็นวิธีที่ง่ายที่สุดดังนั้นคำตอบที่ได้รับความนิยมมากที่สุด แน่นอนว่ามันจะต้องมีความรู้ก่อนดีของ JavaScript
Daniel

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

หรือ

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

// เอาท์พุท: 'gnirts elpmas'


ทั้งหมด 'ส่วน map` [...str]คุณสามารถเขียนเป็น

5

ฉันรู้ว่านี่เป็นคำถามเก่าที่ได้รับการตอบรับเป็นอย่างดี แต่เพื่อความสนุกของตัวเองฉันเขียนฟังก์ชันย้อนกลับต่อไปนี้และคิดว่าฉันจะแบ่งปันในกรณีที่มันมีประโยชน์สำหรับคนอื่น มันจัดการทั้งคู่ตัวแทนและเครื่องหมายรวม:

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

อุปกรณ์ประกอบฉากทั้งหมดเพื่อ Mathias, Punycode และการอ้างอิงอื่น ๆ อีกมากมายสำหรับการสอนฉันเกี่ยวกับความซับซ้อนของการเข้ารหัสอักขระใน JavaScript


4

คุณทำไม่ได้เนื่องจากสตริง JS ไม่เปลี่ยนรูป วิธีแก้ปัญหาแบบไม่เข้าที่สั้น

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


3

หากคุณไม่ต้องการใช้ฟังก์ชันในตัว ลองสิ่งนี้

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

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

console.log(newstring);

2

คำตอบที่แท้จริงคือ: คุณไม่สามารถย้อนกลับได้ แต่คุณสามารถสร้างสตริงใหม่ที่เป็นสิ่งที่ตรงกันข้าม

เช่นเดียวกับการออกกำลังกายเพื่อเล่นกับการเรียกซ้ำ: บางครั้งเมื่อคุณไปสัมภาษณ์ผู้สัมภาษณ์อาจถามคุณถึงวิธีการใช้การสอบถามซ้ำและฉันคิดว่า "คำตอบที่ต้องการ" อาจเป็น "ฉันไม่อยากทำแบบนี้ซ้ำ สามารถทำให้เกิดการล้นสแต็กได้ง่าย "(เพราะมันเป็นO(n)มากกว่าO(log n)ถ้ามันเป็นO(log n)เรื่องยากที่จะได้รับสแต็คล้น - 4 พันรายการสามารถจัดการได้โดยระดับสแต็กที่ 32 เนื่องจาก 2 ** 32 คือ 4294967296 แต่ถ้าเป็นO(n)เช่นนั้นก็สามารถรับล้นสแต็คได้อย่างง่ายดาย

บางครั้งผู้สัมภาษณ์จะถามคุณว่า "เหมือนกับการออกกำลังกายทำไมคุณยังไม่เขียนมันด้วยการเรียกซ้ำ?" และนี่คือ:

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

ทดสอบการทำงาน:

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

เอาท์พุท:

999elppa899elppa...2elppa1elppa0elppa

หากต้องการลองรับสแต็คมากเกินไปฉันเปลี่ยน1000เป็น10000ใน Google Chrome และรายงาน:

RangeError: Maximum call stack size exceeded

2

สตริงจะไม่เปลี่ยนรูป แต่คุณสามารถสร้างสำเนาที่กลับรายการได้อย่างง่ายดายด้วยรหัสต่อไปนี้:

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
นี่มีข้อดีที่จะจัดการกับอักขระระนาบเสริมอย่างถูกต้อง

2

ฟังก์ชั่นขนาดเล็กที่รองรับทั้งการรวมอักขระกำกับเสียงและอักขระ 2 ไบต์:

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


ปรับปรุง

รายการที่สมบูรณ์มากขึ้นของการรวมกำกับกำกับคือ:

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

ความพยายามที่สมน้ำสมเนื้อ แต่ถ้าคุณจะสแกนไฟล์ UnicodeData.txt คุณจะพบว่ามี 316 ช่วงของการรวมกำกับออกเสียงมากกว่า 5
Mr Lister

@MrLister วิธีแก้ปัญหาคือแก้ไขisCombiningDiacriticฟังก์ชั่นให้รวมช่วง 316 ทั้งหมด อย่าลังเลที่จะให้การแก้ไขดังกล่าวเนื่องจากคุณมีข้อมูลอยู่ในมือ
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

โดยไม่ต้องแปลงสตริงเป็นอาร์เรย์

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

ใช้ Array.reverse โดยไม่แปลงอักขระเป็นจุดโค้ด

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

สำหรับรุ่นที่สอง: var c = array[i-1]; array[i-1] = array[i]; array[i] = c;ไม่จำเป็นต้องต่อคู่รหัส นอกจากนี้ for-loop ควรเริ่มต้นที่ 1
MT0

รุ่นที่สองไม่ทำงานด้วย'\ud83c\ud83c\udfa5'.reverse()- มันจะส่งออกเช่นเดียวกับอินพุต การเพิ่ม++i;ภายในifคำสั่งควรแก้ไขสิ่งนี้
MT0

ในความคิดที่สอง - สิ่งนี้ไม่ได้รวมการกำกับกำกับเสียง: 'a\u0303bc'.reverse() === 'cba\u0303'ควรกลับมาจริง
MT0

1

ฉันคิดว่า String.prototype.reverse เป็นวิธีที่ดีในการแก้ปัญหานี้ รหัสดังต่อไปนี้;

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

การใช้ฟังก์ชัน Array

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

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

สิ่งนี้ "เข้าแทนที่" ได้อย่างไร?
Sudhansu Choudhary


1

ทำให้มันแห้งและงี่เง่าอย่างง่าย !!

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

ตกลงสวยเรียบง่ายคุณสามารถสร้างฟังก์ชั่นพร้อมห่วงง่ายที่จะทำสตริงกลับสำหรับคุณโดยไม่ต้องใช้reverse(), charAt()ฯลฯ เช่นนี้

ตัวอย่างเช่นคุณมีสตริงนี้:

var name = "StackOverflow";

สร้างฟังก์ชั่นแบบนี้ฉันเรียกมันว่า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;
}

และคุณสามารถเรียกมันว่า:

reverseString(name);

และผลลัพธ์จะเป็น:

"wolfrevOkcatS"

1

วิธีที่ดีที่สุดในการย้อนสตริงใน JavaScript

1) Array.reverse:

คุณอาจกำลังคิดว่าฉันคิดว่าเรากำลังย้อนกลับสตริงทำไมคุณใช้เมธอด Array.reverse การใช้เมธอด String.split เรากำลังแปลงสตริงของเราเป็นอาเรย์ของตัวละคร จากนั้นเราจะกลับคำสั่งของแต่ละค่าในอาร์เรย์และในที่สุดเราก็แปลง Array กลับเป็น String โดยใช้วิธี Array.join

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

2) Decrementing while-loop:

แม้ว่า verbose สวยโซลูชั่นนี้มีข้อดีกว่าโซลูชันหนึ่ง คุณไม่ได้สร้างอาร์เรย์และคุณเพียงแค่เชื่อมสตริงตามอักขระจากสตริงต้นทาง

จากมุมมองประสิทธิภาพหนึ่งนี้อาจให้ผลลัพธ์ที่ดีที่สุด (แม้ว่ายังไม่ได้ทดสอบ) สำหรับสตริงที่ยาวมาก ๆ ประสิทธิภาพที่เพิ่มขึ้นอาจทำให้หน้าต่างหลุด

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

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


    return temp;
}
reverseString('dwayne');

3) การเรียกซ้ำ

ฉันชอบความเรียบง่ายและชัดเจนของการแก้ปัญหานี้ คุณสามารถเห็นได้อย่างชัดเจนว่ามีการใช้วิธีการ String.charAt และ String.substr เพื่อส่งผ่านค่าที่แตกต่างกันโดยการเรียกตัวเองทุกครั้งจนกว่าสตริงจะว่างเปล่าซึ่งสตริงที่สามจะส่งคืนสตริงว่างแทนที่จะใช้การเรียกซ้ำเพื่อเรียกตัวเอง . นี่อาจจะให้ประสิทธิภาพที่ดีที่สุดเป็นอันดับสองหลังจากการแก้ปัญหาครั้งที่สอง

function reverseString(str) {
    return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.