φυβλαςのβλογ
บล็อกของ phyblas



การใส่ความสามารถเพิ่มเติมให้สายอักขระใน javascript สามารถใช้ sprintf ได้
เขียนเมื่อ 2019/07/07 14:45
แก้ไขล่าสุด 2021/09/28 16:42
ใครที่เคยใช้ภาษาซี หรือไพธอน รูบี หรือ PHP มาก่อน คงจะชินกับการแปลงข้อมูลตัวเลขเป็นสายอักขระโดยใช้ %d %f %x พวกนี้

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

ฟังก์ชันนี้แรกเริ่มเดิมทีมาจากภาษาซี โดยที่เวลาใช้ฟังก์ชัน printf จะกำหนดรูปแบบแล้วก็ตัวแปรที่จะแทนค่าเข้าไปได้อิสระ เช่น printf("%02d__%.3f",1,2) จะแสดงค่า 01__2.000 ออกมา

แต่ถ้าแค่ต้องการแปลงเป็นสายอักขระเฉยๆเก็บไว้ในตัวแปรปกติจะใช้ฟังก์ชันชื่อ sprintf แทน

ฟังก์ชัน sprintf ได้ถูกนำมาใส่ใน PHP เช่นกัน วิธีใช้ก็เหมือนในภาษาซี http://www.w3school.com.cn/php/func_string_sprintf.asp

ไพธอนและรูบีก็ได้นำความสามารถของฟังก์ชันนี้มาใช้ แต่ปรับให้ใช้กับตัวดำเนินการ % แทน

เช่น ถ้าเป็นในไพธอน ปกติเขียนสายอักขระแล้วต่อด้วย % แล้วตามด้วยทูเพิลของค่าที่ต้องการป้อนเข้า เช่น แบบนี้ '%06d %.5f'%(112,129.3) จะได้ '000112 129.30000'

ส่วนในรูบีจะเขียนเป็น '%06d %.5f'%[112,129.3] ผลที่ได้ก็เหมือนกัน

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

ใช่แล้ว เมื่อไม่มีอยู่ก็สร้างขึ้นมาใหม่ซะเองเลยสิ

ว่าแล้วก็ลองเขียนขึ้นเองดูโดยใช้เรกูลาร์เอ็กซ์เพรชชัน (regex)

เราสามารถใส่เมธอดใหม่ให้คล้ายกับเวลาที่ไพธอนหรือรูบีใช้ % โดยในที่นี้จะให้เขียนเป็น '%06d %.5f'.$(112,129.3) ที่จริงอยากให้ใช้ % ได้เหมือนกัน แต่ไม่มีวิธีที่จะทำได้ เลยใช้ $ แทน

หากใส่ฟังก์ชันลงไปให้ String.prototype.$ ก็จะสามารถเรียกใช้ได้จากสายอักขระทุกตัว

ต่อไปนี้เป็นโค้ดที่ใช้
String.prototype.$ = function(...a) {
  var i = -1;
  var re = /(%+)(\+)?((0)?\d+)?(\.(\d+))?([bcdefosuxX])/g;
  var f = function(...m) {
    /* คำอธิบายตัวแปร
    m[1]: กลุ่มเครื่องหมาย % ด้านหน้า
    m[2]: เครื่องหมาย +
    m[3]: ส่วนที่บอกว่าจะเติมสายอักขระให้ยาวอย่างต่ำกี่ตัว
    m[4]: ส่วนที่บอกว่าจะเติมเลข 0 หรือช่องว่าง
    m[5]: ส่วนที่บอกว่าจะเอาเลขทศนิยมกี่ตำแหน่ง
    m[6]: จำนวนตำแหน่งทศนิยม
    m[7]: [bcdefosuxX] ตัวกำหนดประเภท
    */

    // จัดการกับเครื่องหมาย % ด้านหน้า
    var s = m[1].replace(/%%/g, "%");
    // ถ้าจำนวน % เป็นเลขคู่ ไม่ต้องทำอะไร
    if (m[1].length % 2 == 0) {
      return s + [m[2],m[3],m[5],m[7]].join("");
    } // ถ้าจำนวน % เป็นเลขคี่ ให้จัดการแทนค่า
    else {
      s = s.slice(1); // เอา % ออกไปหนึ่งตัว
      i++;
    }

    // ใส่เรื่องหมายบวกถ้าค่าเป็นบวกและไม่ใช่สายอักขระ
    if (m[2] && m[7] != "s" && a[i] > 0) {
      var buak = "+";
    } // ถ้าเป็นลบหรือเป็นสายอักขระไม่ต้องใส่
    else var buak = "";

    // ถ้าเลือกเติม 0 เครื่องหมายบวกใส่ด้านหน้า
    if (m[4] == "0") s += buak;

    // แปลงข้อมูลตามชนิดที่ใส่มา
    // เลขฐาน 2
    if (m[7] == "b") {
      var kaen = a[i].toString(2);
    } // โค้ดตัวหนังสือ
    else if (m[7] == "c") {
      var kaen = String.fromCharCode(a[i]);
    } // เลขจำนวนเต็ม
    else if (m[7] == "d" || m[7] == "u") {
      var kaen = a[i].toString();
    } // เลขทศนิยมในรูป E
    else if (m[7] == "e") {
      if (m[5]) var kaen = a[i].toExponential(m[6]);
      else var kaen = a[i].toExponential();
    } // เลขทศนิยม
    else if (m[7] == "f") {
      var kaen = parseFloat(a[i]);
      if (m[5]) kaen = kaen.toFixed(m[6]);
    } // เลขฐาน 8
    else if (m[7] == "o") {
      var kaen = a[i].toString(8);
    } // เลขฐาน 16 ใช้ตัวพิมพ์เล็ก
    else if (m[7] == "x") {
      var kaen = a[i].toString(16);
    } // เลขฐาน 16 ใช้ตัวพิมพ์ใหญ่
    else if (m[7] == "X") {
      var kaen = a[i].toString(16).toUpperCase();
    } // สายอักขระธรรมดา
    else var kaen = a[i];

    // ใส่ 0 หรือช่องว่าง
    if (m[3]) {
      var n0 = parseInt(m[3]) - (kaen.length + buak.length);
      while (n0 > 0) {
        n0--;
        // ใส่ 0
        if (m[7] != "s" && m[4] == "0") s += "0";
        // ใส่ช่องว่าง
        else s += " ";
      }
    }

    // ถ้าเลือกเติมช่องว่าง เครื่องหมายบวกใส่ด้านหลัง
    if (!m[4]) s += buak;

    return s + kaen;
  };
  return this.replace(re, f);
};

// ทดลองใช้
var ss = `%+04d
%+3d
%%d
%%%%02d
%d
%8.3f
%9.3e
%03o
%05x
%+07X
%b
%c
%7s`;
alert(ss.$(1, -2, 3, 4.2, 0.0053, 9, 315, 315, 61, 100, "ห"));
ผลที่ได้
+001
-2
%dd
%%020d
3
  4.200
5.300e-3
011
0013b
+00013B
111101
d
    ห
ที่จริงผลบางส่วนอาจไม่ได้เหมือนกับ sprintf ของจริงทั้งหมด แต่ก็ถือว่าใช้แทนได้ตามวัตถุประสงค์ที่ต้องการ

ข้างล่างนี้คือพื้นที่ทดสอบ sprintf โดยใช้โค้ดข้างต้นนี้ในการแปลงอักษร ลองทดสอบใช้กันดูได้

sprintf

ข้อมูล
สายอักขระ
ผลลัพธ์



-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> javascript

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

ไทย

日本語

中文