ThaiBreak — Fast Thai Word Segmenter & Typographic Line Breaker
ระบบตัดคำและตัดแบ่งบรรทัดภาษาไทยประสิทธิภาพสูงแบบ Multi-Language Engine รองรับ PHP / Laravel, Go, TypeScript / Node.js, Rust Core, C / C++, Python, และ WebAssembly
ใช้อัลกอริทึม Shortest Path Viterbi DAG ร่วมกับ Theeramunkong 30-Rule Thai Character Cluster (TCC) บนพจนานุกรมมาตรฐานภาษาไทย (data/words.txt 25,804 คำ)
🚀 Zero External Corpus Dependency: ไม่พึ่งพาคลังข้อความที่มีข้อจำกัดทางลิขสิทธิ์ เป็น Open Source Apache-2.0 แท้ 100% ใช้งานเชิงพาณิชย์ได้อย่างสบายใจ
⚡ ความเร็วสูงระดับไมโครวินาที: ~30-45 µs ใน Go/Rust, ~0.3 ms ใน PHP/Node.js (~25,000 ประโยค/วินาทีต่อ core)
💾 Ultra-Lightweight & Low Memory: พจนานุกรมบีบอัดแบบ Compact DAWG (171 KB) และ FST (296 KB) ใช้ RAM ต่ำกว่า 0.2–0.5 MB (ลดลง 95%)
📄 Typographic Line Breaker & Soft Wrapping: ตัดแบ่งบรรทัดป้องกันสระลอย/ตกขอบ ตาม Unicode UAX #14 (Unicode 16.0) ครบทุกกฎ ผ่านชุดทดสอบทางการของ Unicode และ W3C tlreq สำหรับ PDF (dompdf, mPDF, TCPDF, Typst) และ Web
🔥 พร้อมใช้งานกับ Laravel: Auto-Discovery, Facade, Blade Directives (@thaibreak, @thaiwrap), Str Macros
คุณสมบัติเด่น
- Shortest Path Graph Viterbi Algorithm: อัลกอริทึมค้นหาเส้นทางคำที่เหมาะสมที่สุดบนกราฟ ค้นหาคำที่ยาวและถูกต้องสมบูรณ์ตามธรรมชาติ
- Theeramunkong et al. TCC Grammar (30 Rules): คำนวณจุดตัดคลัสเตอร์ภาษาไทยระดับไบต์ออฟเซ็ต ป้องกันการตัดแยกสระ สระบน-ล่าง วรรณยุกต์ หรือพยัญชนะนำ 100%
- FST & Compact DAWG Dictionary Architecture (v1.1.0): โครงสร้างข้อมูลพจนานุกรม Finite State Transducer / Minimal Acyclic DFA บีบอัดคลังคำ 25,804 คำเหลือเพียง 171 KB โหลดทันใจระดับไมโครวินาที (0.04 ms ใน Go, 0.7 ms ใน Node.js, 0.00 ms ใน Rust/OPcache) พร้อมรองรับ Dynamic Overlay เมื่อมีการเพิ่มคำใหม่ขณะรันไทม์
- Smart OOV & Abbreviation Handling: รู้จักคำย่อภาษาไทย (
รพ.,พ.ศ.,มิ.ย.), ตัวเลขคั่นจุลภาค (10,000), ทศนิยม (3.14), เปอร์เซ็นต์ (40%) - ThaiLineBreaker (UAX #14 & W3C Thai Text Layout): ตัดแบ่งบรรทัดสำหรับทำ PDF หรือเว็บด้วย Unicode Line Breaking Algorithm ครบทุกกฎ (LB1–LB31) ใช้พจนานุกรมตัดคำเฉพาะภายในช่วงอักษรไทย ไม่ตัดกลางคำ ตัวเลข คำย่อ หรืออีเมล ไม่ทิ้งวรรคไว้หน้าบรรทัดใหม่ ป้องกันเครื่องหมายตกค้าง (
ๆ,ฯ, วงเล็บ, อัญประกาศ) - HTML / EPUB Safe: รักษาแท็ก HTML (
<p>,<b>,<span>) และ HTML Entities (&,") ให้คงอยู่สมบูรณ์ ไม่แทรกสัญลักษณ์ตัดคำเข้าไปภายในแท็ก
รองรับหลายภาษาโปรแกรม (Multi-Language Architecture)
ThaiBreak ได้รับการออกแบบสถาปัตยกรรมแบบ Monorepo เพื่อรองรับการใช้งานในทุก Stack โดยใช้คลังคำศัพท์มาตรฐาน (data/words.txt: 25,804 คำ) เป็น Single Source of Truth:
thai-break/
├── data/ # Shared Dictionaries (words.dawg: 171 KB, words.fst: 296 KB, words.php, words.txt)
├── php/ # Native PHP & Laravel Package (Composer: kamthorn/thai-break)
│ ├── src/ # PHP Source & Laravel Integration
│ ├── tests/ # PHPUnit & Integration Tests
│ └── examples/ # Demo Scripts
├── go/ # Native Go Package (go get github.com/kamthorn/thai-break/go)
├── typescript/ # Native TypeScript / Node.js Package (npm: thai-break)
├── rust/ # High-Performance Rust Core (Cargo: thaibreak)
│ ├── include/ # C / C++ Header (thaibreak.h)
│ └── src/ # Core Engine + C FFI + Python (PyO3) + Wasm (wasm-bindgen)
├── python/ # Python Package (pip: thaibreak)
└── tools/ # Dev tools: line-break table generator, CLI segmenter, accuracy benchmark
1. PHP & Laravel
การติดตั้งผ่าน Composer
composer require kamthorn/thai-break
การใช้งานทั่วไป (One-liner Quick Start)
use ThaiBreak\ThaiBreak;
// 1. ตัดคำเป็น Array
$words = ThaiBreak::words('ฉันรักภาษาไทย');
// → ['ฉัน', 'รัก', 'ภาษา', 'ไทย']
// ตำแหน่งขอบเขตคำแบบ BreakIterator (นับไบต์ สำหรับ substr(); ส่ง true เป็นอาร์กิวเมนต์ที่สองเพื่อนับตัวอักษร สำหรับ mb_substr())
$bounds = ThaiBreak::boundaries('ฉันรักภาษาไทย');
// → [0, 9, 18, 30, 39]
// 2. ตัดคำคั่นด้วยเครื่องหมาย
$joined = ThaiBreak::join('สวัสดีครับคุณลูกค้า', '|');
// → "สวัสดี|ครับ|คุณ|ลูกค้า"
// 3. แทรกจุดตัดบรรทัด (Zero-Width Space U+200B) สำหรับ Render PDF/HTML
$lines = ThaiBreak::lines('ข้อความยาวๆ ที่ต้องการจัดหน้าใน PDF');
// 4. ตัดแบ่งบรรทัดสำหรับ HTML (รักษาแท็กและ entities)
$html = ThaiBreak::lines('<p>สวัสดี <b>ประเทศไทย</b> & กรุงเทพมหานคร</p>', isHtml: true);
// 5. Hard Wrap ตัดข้อความขึ้นบรรทัดใหม่ตามความกว้างคอลัมน์ (Display Width)
$wrapped = ThaiBreak::wrap('ข้อความภาษาไทยขนาดยาว...', width: 40);
การใช้งานใน Laravel
ThaiBreak รองรับ Laravel Package Auto-Discovery อัตโนมัติ:
use ThaiBreak; // Facade
// เรียกผ่าน Facade
$words = ThaiBreak::words('ข้อความ');
// หรือเรียกผ่าน Str Macro
$words = Str::thaiWords('ฉันรักภาษาไทย');
$html = Str::thaiLines('ข้อความในหน้าเว็บ');
$pdf = Str::thaiWrap($text, 40);
ใน Blade Template:
{{-- แทรก Zero-Width Space เพื่อให้ Browser/PDF ตัดคำได้สวยงาม --}}
@thaibreak($post->content)
{{-- ตัดบรรทัดจำกัดความกว้าง 40 ตัวอักษร --}}
@thaiwrap($report->summary, 40)
การกำหนดพจนานุกรมเพิ่มเติม (Custom Dictionary)
use ThaiBreak\DictionaryLoader;
use ThaiBreak\ThaiTokenizer;
// ตัวเลือกที่ 1: Compact DAWG 171 KB (แนะนำ - โหลดใน 0.3 ms แรม < 0.5 MB)
$trie = DictionaryLoader::fromDawgFile('data/words.dawg');
// ตัวเลือกที่ 2: OPcache Preload (0.00 ms โหลด แรม 0 MB ต่อ worker)
// $trie = DictionaryLoader::fromPhpFile('data/words.php');
// เพิ่มคำศัพท์ใหม่แบบ Dynamic ได้ทันที
$trie->add('คำศัพท์เฉพาะทาง', 10.0);
$tokenizer = new ThaiTokenizer($trie);
$words = $tokenizer->tokenize('ข้อความ...');
2. Go (Golang) — Native Implementation
เขียนด้วย Pure Go 100% ไม่พึ่งพา CGO (CGO_ENABLED=0) ความเร็วสูง ~30-45 µs ต่อประโยค:
go get github.com/kamthorn/thai-break/go
package main
import (
"fmt"
tb "github.com/kamthorn/thai-break/go"
)
func main() {
// ตัดคำ
words := tb.Words("ฉันรักภาษาไทย")
fmt.Println(words) // [ฉัน รัก ภาษา ไทย]
// ตำแหน่งขอบเขตคำแบบ BreakIterator (นับไบต์ ใช้กับ text[b[i]:b[i+1]])
bounds := tb.Boundaries("ฉันรักภาษาไทย") // [0 9 18 30 39]
// แทรกจุดตัดบรรทัด (Zero-Width Space U+200B)
lines := tb.Lines("สวัสดีครับคุณลูกค้า", false)
// ป้องกันแท็ก HTML และ Entity
html := tb.Lines("<b>สวัสดี</b> & ประเทศไทย", true)
// ตัดบรรทัดตามความกว้างหน้าจอ (คำนวณสระ/วรรณยุกต์ไม่คิดความกว้าง)
wrapped := tb.Wrap("ข้อความภาษาไทยยาวๆ...", 40)
fmt.Println(wrapped)
}
3. TypeScript & JavaScript (Node.js / Browser) — Native Implementation
เขียนด้วย TypeScript (ES2022 / NodeNext) ทำงานได้ทั้ง Node.js, Bun, Deno และ Browser:
npm install thai-break
import { words, boundaries, lines, wrap, displayWidth } from 'thai-break';
// ตัดคำ
const tokens = words('ฉันรักภาษาไทย');
console.log(tokens); // ['ฉัน', 'รัก', 'ภาษา', 'ไทย']
// ตำแหน่งขอบเขตคำแบบ BreakIterator (UTF-16 ตรงกับ string.slice)
console.log(boundaries('ฉันรักภาษาไทย')); // [0, 3, 6, 10, 13]
// ตัดบรรทัดสำหรับ HTML (รักษาแท็กและ entities ไม่เสียหาย)
const htmlWithZwsp = lines('<div class="header"><b>สวัสดี</b> & ประเทศไทย</div>', true);
// ตัดบรรทัดจำกัดความกว้างคอลัมน์ (Display Width)
const wrapped = wrap('ฉันรักภาษาไทยมากที่สุดในโลก', 12);
console.log(wrapped);
// คำนวณความกว้างตัวอักษรจริง (สระบน-ล่าง/วรรณยุกต์ = 0, CJK = 2)
console.log(displayWidth('ภาษาไทย')); // 7
4. Rust Core Engine (thaibreak)
ประสิทธิภาพสูงสุดระดับ Native Machine Code ผ่าน Cargo:
[dependencies]
thaibreak = "1"
พจนานุกรมพื้นฐาน (words.fst, 296 KB) ฝังอยู่ในไลบรารีแล้ว (feature embedded-dict เปิดเป็นค่าเริ่มต้น) จึงเรียก words() ได้ทันทีโดยไม่ต้องมีไฟล์ หากต้องการใช้พจนานุกรมของตัวเองเท่านั้น ให้ใช้ default-features = false
use thaibreak::{words, lines, wrap, display_width, DEFAULT_BREAK_MARKER};
fn main() {
let tokens = words("ฉันรักภาษาไทย");
println!("{:?}", tokens); // ["ฉัน", "รัก", "ภาษา", "ไทย"]
let html = lines("<p>สวัสดีชาวโลก</p>", DEFAULT_BREAK_MARKER, true);
println!("{}", html);
let width = display_width("ภาษาไทย");
println!("Width: {}", width); // 7
}
5. C & C++ (ผ่าน C-ABI Shared / Static Library)
เชื่อมต่อได้ทั้ง C, C++, Qt, หรือภาษาใดๆ ที่รองรับ C-ABI:
#include <stdio.h>
#include "thaibreak.h"
int main() {
// โหลดพจนานุกรม FST (เร็วขึ้น 70x และประหยัดแรม) หรือส่ง NULL เพื่อโหลดอัตโนมัติ
thaibreak_init("data/words.fst", NULL);
// ตัดคำ
size_t count = 0;
char **tokens = thaibreak_tokenize("ฉันรักภาษาไทย", &count);
for (size_t i = 0; i < count; i++) {
printf("[%zu] %s\n", i, tokens[i]);
}
thaibreak_free_tokens(tokens, count);
// แทรกจุดตัดบรรทัดใน HTML
char *broken = thaibreak_lines("<b>สวัสดี</b> ประเทศไทย", NULL, 1);
printf("%s\n", broken);
thaibreak_free_string(broken);
return 0;
}
คอมไพล์ด้วย GCC / Clang:
gcc -I rust/include main.c -L rust/target/release -lthaibreak -o app
6. Python (ผ่าน C-FFI / PyO3)
pip install thaibreak
แพ็กเกจเป็น wheel แยกตามแพลตฟอร์ม (py3-none-<platform>) ที่มีไลบรารี Rust และพจนานุกรมพื้นฐาน (words.fst) ติดมาด้วย ใช้ได้กับ Python 3.9 ขึ้นไป (ทดสอบ 3.9–3.13) โดยไม่ต้องติดตั้ง Rust: Linux x86_64/aarch64 (glibc 2.28+), macOS x86_64/arm64 และ Windows x64 แพลตฟอร์มอื่น (เช่น Alpine/musl) ต้อง build เองตามด้านล่าง
import thaibreak
# ไม่ต้องเรียก init ก็ใช้งานได้ (โหลดพจนานุกรมพื้นฐานที่ติดมากับแพ็กเกจ)
# หรือระบุพจนานุกรมเอง เช่น thaibreak.init("data/words.fst")
# ตัดคำ
tokens = thaibreak.words("ฉันรักภาษาไทย")
print(tokens) # ['ฉัน', 'รัก', 'ภาษา', 'ไทย']
# ตำแหน่งขอบเขตคำแบบ BreakIterator (index ของ str; ช่องว่างและเครื่องหมายเป็น segment ด้วย)
text = "ฉันรักภาษาไทย"
b = thaibreak.boundaries(text) # [0, 3, 6, 10, 13]
segments = [text[i:j] for i, j in zip(b, b[1:])]
# แทรกจุดตัดบรรทัดสำหรับ HTML
html = thaibreak.lines("<b>สวัสดี</b> & ประเทศไทย", is_html=True)
# ตัดบรรทัดตามความกว้าง
wrapped = thaibreak.wrap("ฉันรักภาษาไทยมากที่สุดในโลก", width=12)
print(wrapped)
Build wheel เอง (ต้องมี Rust และ Python):
tools/build_python_wheel.sh # ได้ไฟล์ใน python/dist/
GitHub Actions workflow python-wheels.yml build wheel ครบทุกแพลตฟอร์มและอัปโหลดเป็น artifact python-wheels (ไม่ publish ขึ้น PyPI ให้อัตโนมัติ)
7. WebAssembly (Wasm)
คอมไพล์เป็น Wasm สำหรับ Edge/Cloudflare Workers หรือเบราว์เซอร์:
cd rust && wasm-pack build --target web --features wasm
import init, { WasmThaiBreak } from './pkg/thaibreak.js';
await init();
const tb = WasmThaiBreak.withDefault(); // ใช้พจนานุกรมพื้นฐานที่ฝังในโมดูล
// const tb = new WasmThaiBreak(dictTextString); // หรือส่งพจนานุกรมของคุณเอง (TSV)
console.log(tb.words("ฉันรักภาษาไทย"));
console.log(tb.boundaries("ฉันรักภาษาไทย")); // ตำแหน่ง UTF-16 ตาม string index ของ JS
กฎเกณฑ์สำคัญของการตัดบรรทัด (ThaiLineBreaker)
ปัญหาคลาสสิกของการ Render PDF และ EPUB ภาษาไทยคือโปรแกรมตัดคำไทยไม่เป็น ทำให้ข้อความล้นตกขอบ หรือตัดคำแยกกลางสระ/กลางพยางค์
ThaiBreak ใช้ Unicode Line Breaking Algorithm (UAX #14) ของ Unicode 16.0 ครบทุกกฎ (LB1–LB31) โดยอ่านคลาส Line_Break ของทุกอักขระจากฐานข้อมูล Unicode (UCD) และตรวจกับชุดทดสอบทางการ LineBreakTest.txt ผ่านครบทั้ง 16,672 กรณีในทั้ง 4 ภาษา (PHP, Go, Rust, TypeScript; Python ใช้ Rust):
- พจนานุกรมเฉพาะในช่วงอักษรไทย (SA, LB1): UAX #14 กำหนดให้ตัดภายในช่วงอักษรไทยด้วยพจนานุกรม ThaiBreak ใช้ผลตัดคำเป็นจุดตัดบรรทัดเฉพาะระหว่างอักษรไทยกับอักษรไทย เมื่ออักษรไทยอยู่ติดกับอักขระอื่นจะถือเป็นตัวอักษร (AL) จึงไม่ตัด
ราคา100บาท,ปี๒๕๖๗นะ,ภาษาPHPเป็น,ไทย(สยาม)เป็น,«ไทย»ไทย - ส่วนขยายเฉพาะภาษาไทย (Tailoring): ไม้ยมก (
ๆ) และไปยาลน้อย (ฯ, รวมถึงฯลฯ) ไม่ขึ้นต้นบรรทัดใหม่ แม้มีวรรคคั่นอยู่ข้างหน้า (เด็ก ๆ) ตาม W3C tlreq เป็นกฎเดียวที่เพิ่มเติมจาก UAX #14 - ห้ามขึ้นต้นบรรทัด: เครื่องหมายปิดและวรรคตอน (
),],},、,。,!,?,,,.,:,;,/; LB13, LB15d) ยัติภังค์และขีด (-,–,๚,๛; LB21) - ห้ามลงท้ายบรรทัด: วงเล็บเปิดแม้มีวรรคตามหลัง (
( ไทย ); LB14) อัญประกาศเปิด (LB15a, LB19) และสัญลักษณ์นำหน้า เช่น฿,$เมื่อตามด้วยตัวเลขหรือตัวอักษร (LB24, LB25) - ไม่ตัดกลางตัวเลข คำย่อ อีเมล:
1/2/2567,10:30,10-20,-5,40%,พ.ศ.2567,รพ.ศิริราช,e.g.,user@example.com(LB23, LB25, LB28, LB29) - จุดตัดภายในคำที่ไม่ใช่ภาษาไทย: ตัดหลังยัติภังค์หรือทับใน URL ได้ตามมาตรฐาน เช่น
state-|of-|the-|art,https://|example.com/|a-|b - ป้องกัน Orphan Spaces: ช่องว่าง (
) เป็นจุดตัดบรรทัดอยู่แล้ว จึงไม่ใส่ break marker ติดกับช่องว่าง ป้องกันไม่ให้เกิดวรรคนำหน้าในบรรทัดใหม่ - คงความถูกต้องของ HTML/EPUB: แท็ก HTML (
<p>,<b>,<span>), บล็อกสคริปต์/สไตล์ (<script>,<style>,<!-- คอมเมนต์ -->) และ HTML Entities (&,") จะถูกรักษาไว้อย่างสมบูรณ์ ตรวจว่าเป็น HTML เฉพาะเมื่อพบแท็กจริง (<ตามด้วยตัวอักษร/!หรือ?) ข้อความอย่างx < 5 และ y > 3จึงไม่ถูกมองเป็นแท็ก (ข้อจำกัด: ข้อความแต่ละช่วงระหว่างแท็กประมวลผลแยกกัน จึงไม่มีจุดตัดตรงรอยต่อแท็ก) wrap()ใช้จุดตัดชุดเดียวกัน: ตัดบรรทัดเฉพาะจุดที่insertLineBreaks()อนุญาตหรือหลังช่องว่าง และเมื่อเปิดcutLongWordsจะตัดคำที่ยาวเกินบรรทัดตามขอบเขต Thai Character Cluster (TCC) ไม่แยกสระหน้าหรือวรรณยุกต์ออกจากพยัญชนะ- คำนวณความกว้างคอลัมน์ถูกต้อง: สระบน-ล่าง วรรณยุกต์ ไม่นับความกว้างคอลัมน์ (
thaiDisplayWidth) ทำให้ตัดบรรทัดได้พอดีความกว้างจริง
ตาราง Line_Break สร้างจาก UCD ด้วย php tools/generate-linebreak-data.php <UNICODE_VERSION> ซึ่งเขียนไฟล์ตารางของทั้ง 4 ภาษาพร้อมกัน
ผลการประเมินความแม่นยำและประสิทธิภาพ (Accuracy & Performance Benchmarks)
ThaiBreak ได้รับการออกแบบให้มีความสมดุลสูงสุดระหว่าง ความแม่นยำทางภาษาศาสตร์ (Linguistic Accuracy), ความเร็วระดับไมโครวินาที (High Throughput), และ ความปลอดภัยทางลิขสิทธิ์ (Commercial Clean Data)
1. ความแม่นยำในการตัดคำ (Accuracy Benchmark)
วัดด้วย tools/benchmark.py ในโปรเจกต์นี้ เทียบกับคำตอบที่ตัดคำไว้แล้ว (Gold Standard) สองชุดพจนานุกรม: ฐานอย่างเดียว (data/words.txt 25,804 คำ พร้อมน้ำหนักคำจาก data/word-weights.tsv ซึ่งเป็นค่าเริ่มต้นของไลบรารี) และ ฐาน + dict-extra (38,535 คำ รวมพจนานุกรมเสริม thai-break-dict-extra ชุดตัดคำ 14,381 คำ ซึ่งเป็นชุดเดียวกับที่ OpenSearch plugin และตัวอย่าง service ใช้ โดยคำของฐานใช้น้ำหนักชุดเดียวกัน):
| ชุดทดสอบ | ฐานอย่างเดียว Word F1 | Boundary F1 | ฐาน + dict-extra Word F1 | Boundary F1 |
|---|---|---|---|---|
| LST20 test (NECTEC, ข่าว) | 87.1% | 93.8% | 84.0% | 92.3% |
| LST20 eval | 83.9% | 91.6% | 80.9% | 90.2% |
| Blackboard Treebank (ระดับคำย่อย, ไม่รวมประโยคที่ซ้ำกับ LST20 train) | 86.8% | 94.1% | 84.5% | 93.1% |
| Wisesight-1000 (โซเชียลมีเดีย, CC0) | 84.8% | 91.2% | 82.8%† | 90.4%† |
- Word F1: นับคำที่ตำแหน่งต้นและท้ายตรงกับคำตอบ Boundary F1: เทียบตำแหน่งจุดตัดระหว่างคำ ข้อความแบ่งเป็นท่อนที่ช่องว่างและขอบเขตประโยค และไม่นับช่องว่าง
- ทำไมสองคอลัมน์: gold ของ LST20 และ Blackboard แยกคำประสมและชื่อเป็นหน่วยย่อย ส่วน dict-extra เก็บคำประสมและชื่อเฉพาะไว้เป็นคำเดียวโดยตั้งใจ เพื่อให้การค้นหาด้วยคำประสมตรงตัวได้น้ำหนักมากขึ้น (ค้นด้วยคำย่อยได้ผ่านโหมด decompound ของ plugin) คะแนนระดับคำจึงต่ำลงเมื่อใช้ dict-extra: บน LST20 test จุดตัดที่ทำนายแม่นขึ้น (precision 90.3% → 91.0%) แต่พบจุดตัดของ gold ได้น้อยลง (recall 97.7% → 93.7%) ตัวเลขนี้วัดการตัดคำเทียบ gold เท่านั้น ไม่ได้วัดคุณภาพการค้นหา ถ้าจะใช้ตัดคำให้ตรงกับแนวทางของคลังข้อความแบบ LST20 ให้ใช้ฐานอย่างเดียว ส่วนการตัดบรรทัดใช้ชุด
words-extra-linesที่ตัดชื่อเฉพาะและคำประสมออกแล้ว - † dict-extra มีคำสแลงที่สกัดจาก Wisesight Sentiment ซึ่งอาจซ้อนกับข้อความของ Wisesight-1000 คอลัมน์นี้จึงไม่ใช่การทดสอบกับข้อมูลที่ไม่เคยเห็น (แต่คะแนนก็ไม่ได้สูงขึ้น)
- คำที่ตัดผิดส่วนใหญ่ไม่มีในพจนานุกรม: บน LST20 eval ประมาณสองในสามของคำที่ตัดผิด เช่นคำประสมภาษาข่าวตามแนวทางของ LST20 (
มีการ,วันที่,ดังกล่าว) การเพิ่มคำด้วยaddCustomWords()หรือพจนานุกรมเสริมจึงเป็นทางปรับแต่งหลัก แต่ผลขึ้นกับว่าคำที่เพิ่มตรงกับแนวทางตัดคำของงานของคุณหรือไม่ (ดูตารางด้านบน) พจนานุกรมแบบ TSV ที่มีน้ำหนักความถี่ของคำจะถูกใช้เป็นความน่าจะเป็นของคำ (unigram) โดยตรง - คลังข้อมูลไม่ได้รวมอยู่ในโปรเจกต์: LST20 ต้องขอจาก NECTEC และใช้ได้ตามข้อตกลงการใช้งาน (งานวิจัย ไม่ใช่เชิงพาณิชย์ และโอเพนซอร์ส ห้ามแจกจ่ายต่อ) Blackboard Treebank มาจากแหล่งข่าวเดียวกัน ส่วน Wisesight-1000 มาจาก PyThaiNLP/wisesight-sentiment — วางไว้เป็นโฟลเดอร์ข้าง
thai-break/(เช่น../LST20_Corpus)
# รันจากโฟลเดอร์รากของ thai-break
# ค่าเริ่มต้นของไลบรารี: รายการคำฐานพร้อมน้ำหนักคำ
python3 tools/benchmark.py --corpus lst20 --corpus-dir ../LST20_Corpus/test \
--dict data/words.txt --weights data/word-weights.tsv
# ภาษาอื่นที่อ่านบรรทัดจาก stdin เช่น PHP
python3 tools/benchmark.py --corpus lst20 --corpus-dir ../LST20_Corpus/test \
--dict data/words.txt --weights data/word-weights.tsv --segmenter-cmd "php tools/segment.php {dict}"
# ฐาน + dict-extra (ใส่ --dict ซ้ำเพื่อรวมพจนานุกรม)
python3 tools/benchmark.py --corpus lst20 --corpus-dir ../LST20_Corpus/test \
--dict data/words.txt --dict ../thai-break-dict-extra/dist/words-extra.tsv --weights data/word-weights.tsv
2. ประสิทธิภาพและการใช้ทรัพยากร (Performance & Resource Benchmarks)
ทดสอบการประมวลผลจริงบน PHP 8.4 (Native In-Memory) ด้วยการรันข้อความซ้ำ 1,000 รอบ:
ก. การใช้หน่วยความจำและเวลาเตรียมระบบ (Footprint & Startup per Language)
| ภาษา / รูปแบบพจนานุกรม | ไฟล์จัดเก็บ | ขนาดไฟล์ | เวลาโหลด (Startup) | RAM Heap ต่อ Worker | Throughput ค้นหาคำ |
|---|---|---|---|---|---|
| Rust (Native FST) | data/words.fst |
296.2 KB | ~0.00 ms (Zero-copy) | 0 Bytes (Buffer) | 17.8 ล้าน lookups/s |
| Go (Compact DAWG) | data/words.dawg |
171.4 KB | 0.04 ms (48 µs) | < 0.2 MB | 24.5 ล้าน lookups/s |
| TypeScript / Node (Compact DAWG) | data/words.dawg |
171.4 KB | 0.70 ms | < 0.3 MB | 31.8 ล้าน lookups/s |
| PHP (Compact DAWG) | data/words.dawg |
171.4 KB | 0.30 ms | < 0.5 MB | 1.75 ล้าน lookups/s |
| PHP (OPcache Preload Array) | data/words.php |
2.5 MB | 0.00 ms (Preload) | 0 MB (Shared Memory) | 6.5 ล้าน lookups/s |
| PHP (Flat TSV Fallback) | data/words.txt |
492.5 KB | 21.6 ms | ~7.0 MB | 6.5 ล้าน lookups/s |
- การติดตั้งเสริมใน PHP: ไม่ต้องใช้ APCu หรือ C-Extension เสริมใดๆ ทำงานบน Pure PHP ได้ทันทีผ่าน Compact DAWG หรือ OPcache Preloading
ข. ความเร็วในการตัดคำและตัดบรรทัด (Throughput & Latency)
| ขนาดข้อความทดสอบ | ความยาว | คำที่ได้ | เวลาประมวลผล (Latency) | ความเร็ว (Throughput) |
|---|---|---|---|---|
| ประโยคสั้น (ข้อความแชท/ค้นหา) | 16 ตัวอักษร | 5 คำ | 0.011 ms (11 ไมโครวินาที) | ~1,440,000 chars/s |
| ประโยคทั่วไป (ข้อความเอกสาร/ข่าว) | 67 ตัวอักษร | 15 คำ | 0.044 ms (44 ไมโครวินาที) | ~1,530,000 chars/s |
| ย่อหน้ายาว (บทความ 1 พารากราฟ) | 351 ตัวอักษร | 78 คำ | 0.213 ms (0.2 มิลลิวินาที) | ~1,650,000 chars/s |
| บทความเต็มหน้า (ข้อความขนาดยาว) | 3,520 ตัวอักษร | 780 คำ | 2.630 ms (2.6 มิลลิวินาที) | ~1,340,000 chars/s |
| HTML Typographic Line Breaking (แทรก ZWSP ตาม UAX #14) | 210 ตัวอักษร | - | 0.170 ms | ~1,240,000 chars/s |
การรันชุดทดสอบ (Tests Across All Languages)
# 1. PHP & Laravel Tests (รวม Unicode LineBreakTest conformance จาก testdata/)
./vendor/bin/phpunit
php php/tests/TokenizerTest.php
# 2. Go Tests & Benchmarks
cd go && go test -v ./... && go test -bench=. ./...
# 3. TypeScript / Node.js Tests
cd typescript && npm run build && npm test
# 4. Rust Core Tests & Build
cd rust && cargo test && cargo build --release
# 5. Python Tests
cd python && python3 -m unittest tests/test_thaibreak.py
# 6. Benchmark Tool Tests (synthetic data only, no corpus needed)
python3 -m unittest discover tools/tests
การจัดทำโค้ดและการเปิดเผยบทบาทของ AI (AI Disclosure & Attribution)
โครงการ ThaiBreak ได้รับการพัฒนา วางสถาปัตยกรรม และกำกับดูแลทิศทางโดยมนุษย์ (Kamthorn Krairaksa) โดยมีการใช้เทคโนโลยีปัญญาประดิษฐ์ (Generative AI) ในรูปแบบ Pair Programming & Multi-Agent Engineering ร่วมจัดทำโค้ดอย่างโปร่งใส ดังนี้:
- Claude Sonnet 4.6 (Anthropic): ร่วมออกแบบโครงสร้างอัลกอริทึมหลัก (Thai Character Cluster: TCC, DAG Word Graph, Viterbi Forward/Backward Dynamic Programming, W3C/Unicode Typographic Line Breaking Rules) และการพัฒนาโค้ด Native ในภาษา PHP, Go, TypeScript รวมถึง Rust Core Engine
- Gemini 3.8 Flash (Google DeepMind): ร่วมวิเคราะห์ประสิทธิภาพ (Performance Optimization), การตรวจสอบความถูกต้องข้ามภาษา (Cross-language Verification), การจัดทำชุดทดสอบรอบด้าน (Test Suites across all 5+ languages), การตรวจสอบความปลอดภัยและการจัดการหน่วยความจำ (Memory Safety & C-FFI Hardening) และการคัดกรองฐานข้อมูลพจนานุกรมให้เป็น Public Domain 100%
โค้ดทุกโมดูลได้รับการออกแบบ ตรวจทาน ปรับแก้สถาปัตยกรรม และผ่านการทดสอบอัตโนมัติ (Automated Unit & Integration Tests) ครบถ้วนทุกภาษา ทั้ง PHP, Go, TypeScript, Rust, C/C++ และ Python เพื่อความมั่นใจในคุณภาพ ความปลอดภัย และความถูกต้องตามหลักภาษาศาสตร์
OpenSearch / Elasticsearch Integration
สำหรับการใช้งาน ThaiBreak engine บน OpenSearch หรือ Elasticsearch ผ่าน Plugin สำเร็จรูป ดูที่:
opensearch-analysis-thaibreak v1.0.0
Plugin OpenSearch ที่ใช้ Viterbi+TCC engine เดียวกัน พร้อม Token Filters ครบชุด:
| Token Filter | คำอธิบาย |
|---|---|
thai_tone |
ลบวรรณยุกต์และไม้ไต่คู้เพื่อค้นหาแบบ Loose |
thai_soundex |
Phonetic matching ด้วย Udom83 Algorithm |
thai_keyboard |
แปลง Kedmanee ↔ QWERTY สำหรับ mis-type |
thai_number |
แปลงเลขไทย (๐-๙) และคำอ่านตัวเลขเป็นอารบิก |
# ติดตั้งสำหรับ OpenSearch 2.18.0
bin/opensearch-plugin install \
https://github.com/kamthorn/opensearch-analysis-thaibreak/releases/download/v1.0.0/analysis-thaibreak-2.18.0.0.zip
รองรับ OpenSearch: 2.11.1 · 2.15.0 · 2.17.1 · 2.18.0 · 2.19.0 · 3.8.0
🔗 github.com/kamthorn/opensearch-analysis-thaibreak
เอกสารอ้างอิง
- Royal Institute Dictionary: พจนานุกรมฉบับราชบัณฑิตยสถาน (Public Domain Standard Thai Wordlist)
- Prachathai-67k: คลังข่าวประชาไท 67,000 บทความ (wannaphong/prachathai67k, Apache-2.0) ใช้นับน้ำหนักความถี่ของคำ
- Thai Character Cluster (TCC): Theeramunkong et al., Multi-segmentation for Thai word extraction, 2000
- Unicode Line Breaking Algorithm: Unicode Standard Annex #14 (UAX #14)
- W3C Requirements for Thai Text Layout: W3C Working Group Note (tlreq)
- License: Apache-2.0
Metadata
Release files for thaibreak 1.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| thaibreak-1.5.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details for thaibreak-1.5.0-py3-none-win_amd64.whl |
| thaibreak-1.5.0-py3-none-manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64 | Details for thaibreak-1.5.0-py3-none-manylinux_2_28_x86_64.whl |
| thaibreak-1.5.0-py3-none-manylinux_2_28_aarch64.whl | Python 3 | none | Linux glibc 2.28+ ARM64 | Details for thaibreak-1.5.0-py3-none-manylinux_2_28_aarch64.whl |
| thaibreak-1.5.0-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details for thaibreak-1.5.0-py3-none-macosx_11_0_arm64.whl |
| thaibreak-1.5.0-py3-none-macosx_10_13_x86_64.whl | Python 3 | none | macOS 10.13+ x86-64 | Details for thaibreak-1.5.0-py3-none-macosx_10_13_x86_64.whl |
Total release size: 4.9 MB
Release files / thaibreak-1.5.0-py3-none-win_amd64.whl
| Download URL | thaibreak-1.5.0-py3-none-win_amd64.whl |
|---|---|
| Size | 886.5 kB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
e489f091ca2a094a618fda2070bb71c0f647bcf19435ae0865135b95a1f907ab
|
|
BLAKE2b-256 checksum How to use checksums |
1eced226c779a952d7c9306a5b5888e0572bea5bb0776771476f1dfb5611e226
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / thaibreak-1.5.0-py3-none-manylinux_2_28_x86_64.whl
| Download URL | thaibreak-1.5.0-py3-none-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.0 MB |
| Tags | Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
38df9bd1a59b89c317f52a54c7ebc7277fdc7c486e896071ede9aed628b649ae
|
|
BLAKE2b-256 checksum How to use checksums |
7cc156c9915fd97accd25058f5b41078fbe173b1942a68cfe0dc6588408c3949
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / thaibreak-1.5.0-py3-none-manylinux_2_28_aarch64.whl
| Download URL | thaibreak-1.5.0-py3-none-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.0 MB |
| Tags | Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
fa376d4c9782b3205bedffba9c013178750765b920584358c96e9e025c55a9b7
|
|
BLAKE2b-256 checksum How to use checksums |
7b61745dcd51075100eda0229ea046a6f1cca1dc72d8e70864065c9a55209360
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / thaibreak-1.5.0-py3-none-macosx_11_0_arm64.whl
| Download URL | thaibreak-1.5.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 956.5 kB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
bb13c157e86c1821829ec0cfbcb2b9ed4c5b064de5027194740c96647fd9426b
|
|
BLAKE2b-256 checksum How to use checksums |
ac920d1c0713aec205e7006f0d11cd3fad88fbe7a6ffa333f8c084fe5ce7c8fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / thaibreak-1.5.0-py3-none-macosx_10_13_x86_64.whl
| Download URL | thaibreak-1.5.0-py3-none-macosx_10_13_x86_64.whl |
|---|---|
| Size | 968.8 kB |
| Tags | Python 3 macOS 10.13+ x86-64 |
|
SHA-256 checksum How to use checksums |
f731ddf077ffb144f6a4a80b083b3cbde5f09a1675d40c88bdc8d8dc5440d0e5
|
|
BLAKE2b-256 checksum How to use checksums |
539e24b280e66f4ab4d40852e467d0bc413845b0e52f7e6a4f31ff2cc76607c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Security for thaibreak 1.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.