วันเสาร์ที่ 5 กรกฎาคม พ.ศ. 2568

การเขียน Regular Expression ตรวจจับตัวอักษรภาษาจีน

ตอนทำไฟล์ ePUB แล้วตัวอักษรภาษาจีนมักจะใหญ่กว่าตัวอักษรไทย เวลาที่ทำหนังสือที่มีอักษรภาษาจีนอยู่ด้วย ถ้าอยากให้ตัวเล็กเท่ากับตัวหนังสือภาษาไทยอื่นๆ ในเล่ม ก็จะใส่ span ครอบไว้ว่าเป็นตัวจีน

แต่ถ้ามีตัวอักษรจีนแทรกอยู่ประปราย จะมานั่งใส่ด้วยมือก็เสียเวลาไม่น้อย ซึ่งใน Sigil ก็สามารถสั่งค้นหาแทนที่จาก Regular Expression ได้

วิธีการคือสั่งค้นหา

/([\x{4e00}-\x{9fff}]+)/u

ถ้าเป็น Sigil ไม่ต้องใส่ // ครอบ คือใช้เป็น

([\x{4e00}-\x{9fff}]+)

แล้วแทนที่ด้วย <span class="">\1</span> หรือ <span class="">$1</span>

แต่ text editor บางตัว จะมีฟังก์ชัน Regular Expression ไม่ครบ (เช่น VS Code, Sublime, Notepad++, Atom) ก็สั่งค้นหาด้วย

[\u4e00-\u9fff]+

หรือ Sublime บางเวอร์ชัน สามารถสั่งค้นด้วย

\p{Han}+


อธิบายเพิ่มเติม

/([\x{4e00}-\x{9fff}]+)/u

จับกลุ่มตัวอักษรจีนทั้งหมด (กลุ่มตัวอักษร CJK - Chinese Japanese Korean Unicode)

พารามิเตอร์ u ตัวท้ายคือใช้ Unicode mode สำหรับภาษาจีน ญี่ปุ่น เกาหลี ฯลฯ

ในส่วนตัวอักษรจีนแบบดั้งเดิม (จีนตัวเต็ม) รหัสที่ใช้จะอยู่ในช่วง \x{3400}-\x{4dbf} หากต้องการให้ตรวจจับด้วยก็เพิ่มเข้าไป


หากต้องการเพิ่มการตรวจจับสัญลักษณ์พิเศษ ,。?!「」 ซึ่งเป็นตัวอักษรแบบ full width ที่ใช้กับภาษาจีน ก็เพิ่มเงื่อนไขการค้นหาเป็น

/([\x{4e00}-\x{9fff}\x{3000}-\x{303f}\x{ff00}-\x{ffef}]+)/u

โดยรหัส unicode ที่ใช้ มีความหมายดังนี้

\x{4e00}-\x{9fff} → อักษรจีน CJK Unified Ideographs

\x{3000}-\x{303f} → เครื่องหมายวรรคตอนจีน เช่น “ ” 『 』 、 。

\x{ff00}-\x{ffef} → Full-width ASCII เช่น ,.!%)


การเขียนเพื่อใช้งานกับ PHP จะอยู่ในรูปแบบ

$text = preg_replace(

    '/([\x{4e00}-\x{9fff}\x{3000}-\x{303f}\x{ff00}-\x{ffef}]+)/u',

    '<span class="zh">$1</span>',

    $text

);


แต่ถ้าอยากให้แยกออกมาเป็นครอบทีละตัวอักษรก็ตัดเครื่องหมายบวกที่ท้ายสุดออก เป็นแบบนี้

$text = preg_replace(

    '/([\x{4e00}-\x{9fff}\x{3000}-\x{303f}\x{ff00}-\x{ffef}])/u',

    '<span class="zh">$1</span>',

    $text

);



และถ้าต้องการเขียนเป็น JavaScript เพื่อตรวจจับว่าหากมีย่อหน้าไหนเป็นตัวอักษรจีน (CJK) ก็ให้ใส่ lang กำกับไว้ แต่แบบนี้จะเป็นการจัดการทั้งย่อหน้าหรือทั้ง span ซึ่งจะใช้ในกรณีแสดงข้อความจีนบรรทัดไทยบรรทัด เช่นแปลเนื้อเพลง

<script>

document.addEventListener("DOMContentLoaded", function () {

  // ตัวอย่าง: ตรวจเฉพาะ <p> และ <span>

  const elements = document.querySelectorAll("p, span");


  elements.forEach((el) => {

    const text = el.textContent;


    // ตรวจว่ามีอักษรจีนหรือ full-width symbols หรือไม่

    const hasChinese = /[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]/.test(text);


    if (hasChinese) {

      el.setAttribute("lang", "zh");

    }

  });

});

</script>


ตัวอย่าง

<p>นี่คือข้อความภาษาไทย</p>

<p>这是中文段落。</p>

<span>,。?!「」</span>

ผลลัพธ์

<p>นี่คือข้อความภาษาไทย</p>

<p lang="zh">这是中文段落。</p>

<span lang="zh">,。?!「」</span>

การกำหนด css

p:lang(zh), span:lang(zh) {

  font-family: "Noto Sans SC", sans-serif;

  color: crimson;

}


แต่ถ้าเป็นย่อหน้าที่มีทั้งไทยและจีนผสมกัน จะใช้วิธีด้านบนไม่ได้ ต้องเปลี่ยนเป็นวิธีนี้แทน

<script>

document.addEventListener("DOMContentLoaded", function () {

  const elements = document.querySelectorAll("p, span");


  elements.forEach((el) => {

    const html = el.innerHTML;


    // Regex: จับกลุ่มตัวอักษรจีน + full-width symbol

    const replaced = html.replace(

      /([\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+)/g,

      '<span class="zh">$1</span>'

    );


    el.innerHTML = replaced;

  });

});

</script>


ตัวอย่าง

<p>หัววัวไม่ตรงกับปากม้า (牛头不对马嘴) อุปมาถึงสิ่งของสองอย่างที่ไม่เข้ากันแม้แต่น้อย ไม่ได้มีความเกี่ยวข้องสัมพันธ์กัน</p>

ผลลัพธ์

<p>หัววัวไม่ตรงกับปากม้า <span class="zh">(牛头不对马嘴)</span> อุปมาถึงสิ่งของสองอย่างที่ไม่เข้ากันแม้แต่น้อย ไม่ได้มีความเกี่ยวข้องสัมพันธ์กัน</p>


ไม่มีความคิดเห็น:

แสดงความคิดเห็น