โปรแกรมตัดคำภาษาไทยอย่างง่าย สำหรับใช้กับ Python 3

#! -*- coding: UTF8 -*-
from wordcut import Wordcut
if __name__ == '__main__':
    with open('bigthai.txt') as dict_file:
        word_list = [w.rstrip() for w in dict_file.readlines()]
        word_list.sort()
        wordcut = Wordcut(word_list)
        print(wordcut.tokenize("กากา cat หมา"))

ใช้แบบข้างบนเลยครับ โปรแกรมโหลดได้จาก https://gitlab.com/veer66/wordcutpy บน github ก็มีครับชื่อเดียวกันถ้าทนใช้ gitlab ไม่ไหว

ตัวนี้พยายามจะให้มันง่ายนะครับไฟล์เดียวเสร็จเลย ยังไม่ได้ test เยอะ ถ้าเจอปัญหาอะไรแจ้งใน gitlab ได้เลยครับ ถ้ามี testcase ให้เลยจะดีมาก ถ้ามี testcase ด้วย pull request มาด้วยเลยก็จะดีมาก ๆ ครับ 🙂

ป.ล. ใช้ได้กับ Python 3 ขึ้นไปเท่านั้นครับ เพราะว่าพี่ bact ใช้ Python 3 😛

Advertisements

wordcut 0.7.0 เรียกใช้จาก command line ได้แล้วครับ

wordcut คือโปรแกรมตัดคำ (word segmentation)

วิธีติดตั้ง

npm install -g wordcut

เวลาใช้ก็จะประมาณนี้อะครับ

$ wordcut
กากากา
กา กา กา

คือพิมพ์ กากากา เข้าไปมันก็ตัดได้ กา กา กา ออกมา

More info: http://github.com/veer66/wordcut

โปรแกรมตัดคำ แบบใช้ PHP ล้วน ๆ

ที่ผ่านมามีหลายท่านสนใจถามเข้าหลังจากที่แสดงตัวอย่างเรียก Swath จาก PHP ให้ดู แต่ส่วนมากพอใช้บน Windows หลายคน ก็งง ๆ ผมก็งง ก็เลยจัดอันนี้ไป โปรแกรมตัดคำมันบน PHP ล้วน ๆ เสียเวลาเขียนไปหลายชั่วโมงอยู่ครับ น่าจะมี bug อะไรเต็มไปหมดถ้าท่านใดพบกรุณาแจ้งไปที่ https://github.com/veer66/PhlongTaIam/issue เดี๋ยวนี้ใช้ github แล้วครับ เพื่อท่านใดจะช่วยแก้จะได้ fork แล้ว pull request กลับมาได้เลย ไม่ต้องเสียเวลาย้ายไปย้ายมาให้ลำบากเหมือนโครงการก่อน

เข้าไป download ที่ https://github.com/veer66/PhlongTaIam ได้เลยครับ ถ้าเอาง่าย ๆ ก็ click ที่ปุ่มที่เขียนว่า zip และมีรูปเมฆมีลูกศรชี้ลงครับ ก็ได้ code ไปทั้งหมด เอาไปวางใน htdocs ก็น่าจะใช้ได้เลย

แต่ก็อาจจะเจ๊งบน Windows หรือสิ่งแวดล้อมที่ต่างจากที่ผมใช้อยู่อยู่ดี ถ้าปัญหาอะไรก็ถามไว้ที่นี่ได้ครับ แต่ว่าส่วนมากผมมักจะตอบไม่ได้  แต่ก็เผื่อมีท่านอื่นตอบได้ครับ

ใช้ Swath จาก PHP

Update: โปรแกรมตัดคำแบบใช้ PHP เลยก็มีนะครับ: https://github.com/veer66/PhlongTaIam

ทางบ้านถามเข้ามาหลายท่าน ผมจึงเขียนออกมาได้แบบนี้ครับ

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>Swath Web</title>
	<meta name="generator" content="TextMate http://macromates.com/">
	<meta name="author" content="Vee Satayamas">
	
</head>
<body>
<form method="post">
<textarea name="input_text" cols="80" rows="10"></textarea>
<input type="submit" value="submit">
</form>
<?php

    function swath($input_text) 
    {
        $input_filename= tempnam("/tmp", "swath_");
        $output_filename= tempnam("/tmp", "swath_");
        $input_text_tis620 = iconv("UTF-8", "TIS-620", $input_text);
        file_put_contents($input_filename, $input_text_tis620);
        system("/usr/bin/swath < $input_filename > $output_filename");
        $raw = file_get_contents($output_filename);
        $raw_utf8 = iconv("TIS-620", "UTF-8", $raw);
        unlink($input_filename);
        unlink($output_filename);
        return preg_split('/\|/', $raw_utf8);
    }

    if($_REQUEST['input_text']) {
        $output = swath($_REQUEST['input_text']);
        print implode(" ", $output);
    }
?>
</body>
</html>

แต่ว่าแบบนี้เราต้องลง swath ไว้ใน /usr/bin นะครับ ฯ​ ลงไว้ที่อื่นก็ไม่น่าเป็นไรนะครับ เปลี่ยนใน code เอาเลยก็ได้ ฯ อีกอย่างคือต้องการใช้ iconv ด้วย ฯ แต่ถ้าไม่ใช้ iconv ก็น่าจะได้อีกเหมือนกัน ฯ​ เปลี่ยนหน้าเว็บเป็น TIS-620 ให้หมดก็น่าจะใช้ได้เลย ฯ

การติดตั้งและใช้งาน KUCut บน Windows (XP)

KUCut มีคนถามบ่อยเหมือนกันว่าติดตั้งใช้งานอย่างไร ผมก็เลยเขียนเป็น blog ไว้เลยดีกว่า

  1. ติดตั้ง Python 2.6.2
  2. ขั้นตอนแรกก็ดาวโหลด KUCut มาก่อนจาก kucut-1.2.7.tar.gz
  3. จากนั้นก็แตกไฟล์ zip ที่ดาวโหลดมาแล้วออกมา ในกรณีนี้ผมเก็บไว้ใน Desktop
  4. เรียกใช้งานโปรแกรม command prompt
  5. ใช้คำสั่ง cd เปลี่ยน directory ไปเป็น directory ของ KUCut
    kucut_screen1
  6. ติดตั้ง KUCut ด้วยคำสั่ง
    C:\Python26\python.exe setup.py install
    
  7. ลองสร้างไฟล์ test1.txt เขียนภาษาไทยไว้เพื่อทดสอบ (ใช้ character set TIS-620)
    ผมเขียนสิ่งนี้ลงไป:

    ทดลอง โปรแกรมตัดคำ
    
  8. สั่งตัดคำโดยใช้คำสั่ง
    C:\Python26\python.exe C:\Python26\Scripts\kucut --line="_" test1.txt
    
  9. ก็จะได้ไฟล์ test1.txt.cut ออกมา เปิดดูข้างในก็ควรจะเป็นแบบนี้
    ทดลอง _ โปรแกรม ตัด คำ 
    

เป็นอันเรียบร้อย วิธีใช้จาก Python เดี๋ยวผมจะเขียนอีกทีครับ (ถ้าผมทำได้)

Python libthai binding (th_brk only)

I want to use libthai from Python so I wrote this extension.

#include 
#include "structmember.h"
#include 

static PyObject*
th_brk_(PyObject *self, PyObject *args)
{
    PyObject *result = NULL;

    Py_UNICODE *s1;
    int s1_len;

    if (PyArg_ParseTuple(args, "u#", &amp;s1, &amp;s1_len)) {
        int *pos = (int *)malloc(sizeof(int) * (s1_len + 1));
        PyObject *txt_cp874 = PyUnicode_Encode(s1, s1_len, "CP874", NULL);
        Py_ssize_t len = PyString_Size(txt_cp874);
        char *c_txt_cp874 = PyString_AsString(txt_cp874);
        int n = th_brk((unsigned char *)c_txt_cp874, pos, len);
        int i, s = 0;
        char *buffer = (char *)malloc(sizeof(char) * (s1_len + 1));
        result = PyList_New(0);
        for(i = 0; i &lt; n; i++) {
            PyObject *tok_cp874 = PySequence_GetSlice(txt_cp874, s, pos[i]);
            Py_ssize_t tok_len;
            PyObject *tok;
            PyString_AsStringAndSize(tok_cp874, &amp;buffer, &amp;tok_len);
            tok = PyUnicode_Decode(buffer, tok_len, &quot;CP874&quot;, NULL);
            s = pos[i];
            PyList_Append(result, tok);
        }
        if(s &lt; len) {
            PyObject *tok_cp874 = PySequence_GetSlice(txt_cp874, s, len);
            Py_ssize_t tok_len;
            PyObject *tok;
            PyString_AsStringAndSize(tok_cp874, &amp;buffer, &amp;tok_len);
            tok = PyUnicode_Decode(buffer, tok_len, &quot;CP874&quot;, NULL);
            PyList_Append(result, tok);
        }
        free(pos);
    }
    return result;
}

static PyMethodDef module_methods[] = {
    {&quot;th_brk&quot;, (PyCFunction)th_brk_, METH_VARARGS,
     &quot;Thai word break&quot;},
    {NULL, NULL, 0, NULL}   /* sentinel */
};

#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initlibthai(void)
{
    PyObject* m;
    m = Py_InitModule3(&quot;libthai&quot;, module_methods,
                       &quot;libthai module&quot;);
    if (m == NULL)
      return;
}

แนวทางในการแก้ให้ ICU ตัดคำภาษาลาวได้

หลังจากที่ได้ word list จาก au8ust มาผมก็ยังไม่ได้ทำอะไรกับ word list เลย. แต่เท่าที่ดูแล้วโปรแกรมที่แก้แล้วน่าจะมีประโยชน์กับหลายๆโปรแกรมน่าจะเป็น icu. อย่างเช่น OpenOffice.org เป็นต้น (แต่ก็ไม่รู้ว่าจริงหรือเปล่า)

หลังจากที่ดูคร่าวๆ แล้วไฟล์แรกที่น่าจะต้องแก้น่าจะเป็น source/common/dictbe.h ที่ในนั้นมี ThaiBreakEngine อยู่ ก็เลยคิดว่าก็คงต้องมี LaoBreakEngine ด้วยเหมือนกัน แก้กฎข้างในเล็กๆ น้อยๆ พวกไม้ยมก ก็คงจะไม่เหมือนกันหรือเปล่า … อันนี้ก็ไปแก้ใน source/common/dictbe.cpp

ตอนนี้แผนต่อไปก็คงต้องลงมือทำดูพร้อมเขียน test อะไรประมาณนั้น

ป.ล. libthai ก็ดูน่าสนใจดี มีใช้หลายโปรแกรมเหมือนกัน แต่ libthai ตัดคำภาษาลาวด้วยก็ดูแปลกๆ หรือเปล่า?

ตัดคำโดยใช้ Python และ ICU

ผมดูตัวอย่างมาจาก http://www.thaitux.info/node/194. ผมเลยมาเขียน version ของผมบ้าง เพื่อที่จะเอามาเตรียม corpus สำหรับ bilingual word matching (alignment).

#-*- coding: UTF-8 -*-
import sys
import PyICU

# split_words was inspired by an example in http://www.thaitux.info/node/194

def is_tha(c):
	return ord(c) &gt;= 0x0E00 and ord(c) &lt;= 0x0E7F

def merge(ans, tok):
	if is_tha(tok[0]) or len(ans[:-1]) == 0 or is_tha(ans[-1][0]):
		return ans + [tok]
	else:
		return ans[:-1] + [ans[-1] + tok]

def split_words(txt):
	icu_txt = PyICU.UnicodeString(txt)
	brk_iter = PyICU.BreakIterator.createWordInstance(PyICU.Locale(&quot;th&quot;))
	brk_iter.setText(icu_txt)
	brk_e = [i for i in brk_iter]
	brk_s = [0] + brk_e[:-1]
	ans = [unicode(icu_txt[i[0]:i[1]]) for i in zip(brk_s, brk_e)]
	return filter(lambda t: t != &quot;&quot;, reduce(merge, ans, []))

def main():
	reload(sys)
	sys.setdefaultencoding(&#039;utf-8&#039;)
	print split_words(&quot;ทดลองทดลอง 5%&quot;)

if __name__ == &#039;__main__&#039;:
	main()

ผลออกมาได้ [u'u0e17u0e14u0e25u0e2du0e07', u'u0e17u0e14u0e25u0e2du0e07', u' 5%'] ถ้า print ดีหน่อยๆ มันก้ประมาณว่า ทดลอง|ทดลอง| 5%.ก่อนจะใช้ได้ก็ลง libicu ก่อนโดยใช้ aptitude install libicu-dev แล้วตามด้วย easy_install pyicu (สมมุติว่าลง easy_install กับ python ไว้อยู่แล้วนะครับ)