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



การใส่ความสามารถเพิ่มเติมให้สายอักขระใน javascript สามารถใช้ sprintf ได้
เขียนเมื่อ 2019/07/07 14:45
ใครที่เคยใช้ภาษาซี หรือไพธอน รูบี หรือ 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

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
python
-- numpy
-- matplotlib

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

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



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

  ค้นหาบทความ

  บทความแนะนำ

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

บทความแต่ละเดือน

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2019年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2018年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2017年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2016年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文