वीर

4 มีนาคม 2008

เตรียม parallel corpus สำหรับ word alignment จาก .po

วิธีที่ก็ใช้ polib อ่าน .po ของ GNOME มาแล้วก็พยายาม ตัดเครื่องหมายทิ้ง. แม้แต่ string ที่มีหลายบรรทัดก็ตัดทิ้ง.

ขั้นแรกเลยคือเข้าไปที่ web L10N ของ GNOME http://l10n.gnome.org/languages/th/gnome-2-22 หลังจาก copy & paste และแก้ด้วยความถึกนิดหน่อย ผมก็ได้รายการของ .po มา.

Download po file pessulus       100% (30/0/0)
Download po file Sabayon        100% (230/0/0)
GNOME developer platform (66% translated)
Download po file atk    95% (117/0/6)
Download po file gail   100% (103/0/0)

พอได้แบบนี้มาแล้วก็เขียนโปรแกรมมาตัดๆ หน่อย

get_pkg.rb

while gets
    if $_ =~ /Download po file ([^s]+)/
        print "wget  http://l10n.gnome.org/POT/#{$1}.HEAD/#{$1}.HEAD.th.pon"
    end
end

ก็ได้ script ที่ load .po ออกมา

$ ruby get_pkg.rb > download.sh && sh download.sh

พอได้แบบนี้มาแล้วผมก็เขียนโปรแกรมมา extract ของใน .po มาชื่อ ext_po.py


#-*- coding: UTF-8 -*-
import sys
import polib
import getopt
import re

class Params:
    def __init__(self, o_eng_path, o_tha_path, i_po_paths):
        self.o_eng_path = o_eng_path
        self.o_tha_path = o_tha_path
        self.i_po_paths = i_po_paths

    def __str__(self):
        return str(self.__dict__)

def usage():
    print "Usage: " + sys.argv[0] + " -e  -t   ..."

def usage_and_exit():
    usage()
    sys.exit(2)

def get_params():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "e:t:")
        keys = [o[0] for o in opts]
        if not "-e" in keys:
            print "Require English output filename"
            usage_and_exit()
        if not "-e" in keys:
            print "Require Thai output filename"
            usage_and_exit()
        if len(args) < 1:
            print "Require po filename"
            usage_and_exit()
        return Params(o_eng_path = filter(lambda o: o[0] == "-e", opts)[0][1],
                      o_tha_path = filter(lambda o: o[0] == "-t", opts)[0][1],
                      i_po_paths = args)
    except getopt.GetoptError, err:
        print str(err)
        usage_and_exit()

def entry_constraints(entry):
    return not entry.translated() and entry.msgstr != ""
        and entry.msgid != ""

def remove(txt, sym):
    return re.sub(sym, " ", txt)

def convert_text(txt):
    syms = ["_", "...", ":", "|", "-+", "/+", "%w", "",
            """, "©", "~", "(", ")"]
    return reduce(remove, syms, txt)

def split_line(txt):
    return filter(lambda tok: not re.match("^ *$", tok),
                  re.split("n", txt))

def split_line_in_entry(ans, entry):
    e_lines = split_line(entry[0])
    t_lines = split_line(entry[1])
    if len(e_lines) == 1 and len(t_lines) == 1:
        return ans + [(e_lines[i], t_lines[i]) for i in range(len(e_lines))]
    else:
        return ans

def ext_po_file(o_eng_file, o_tha_file, po):
    entries = filter(entry_constraints, list(po))
    entries = [(entry.msgid, entry.msgstr) for entry in entries]
    entries = [(convert_text(e[0]), convert_text(e[1])) for e in entries]
    entries = reduce(split_line_in_entry, entries, [])
    for entry in entries:
        o_eng_file.write(entry[0] + "n")
        o_tha_file.write(entry[1] + "n")

def ext_with_ofiles(o_eng_file, o_tha_file, i_po_paths):
    for i_po_path in i_po_paths:
        po = polib.pofile(i_po_path)
        ext_po_file(o_eng_file, o_tha_file, po)    

def ext(o_eng_path, o_tha_path, i_po_paths):
    o_tha_file = open(o_tha_path, 'w')
    o_eng_file = open(o_eng_path, 'w')
    ext_with_ofiles(o_eng_file, o_tha_file, i_po_paths)
    o_eng_file.close()
    o_tha_file.close()

def init_charset():
    reload(sys)
    sys.setdefaultencoding('utf-8')

def main():
    init_charset()
    params = get_params()
    ext(params.o_eng_path, params.o_tha_path, params.i_po_paths)

if __name__ == '__main__':
	main()

จากนั้นก็สั่ง (โดยสมมุติว่า .po ทั้งหมดอยู่ใน folder เดียวกัน)

$ python ext_po.py -e e -t t  *.po

cut.sh เอาไว้ตัดคำโดยใช้  kucut อีกที

#!/bin/sh
iconv -f UTF-8 -t TIS-620 < $1 > $1.tis
kucut –line=” ” $1.tis
iconv -f TIS-620 -t UTF-8 < $1.tis.cut > $1.cut

แล้วก็ใช้ cut.sh โดยเรียก

$ ./cut.sh t && mv t.cut t

จากนั้นก็ไปเรียก GIZA++ แบบที่แก้ๆไปแล้ว ได้เลย

$ plain2snt e t

$ train-giza++ e.vcb t.vcb e_t.snt

เป็นอันเรียบร้อย

ได้ผลออกมาแบบนี้

# Sentence pair (1) source length 6 target length 6 alignment score : 0.000163118
รายการ เมนู ใหม่ ต้อง มี ชื่อ
NULL ({ }) New ({ 3 }) menu ({ 2 }) items ({ 1 }) need ({ 4 5 }) a ({ }) name ({ 6 })
# Sentence pair (2) source length 5 target length 5 alignment score : 0.00022357
เมนู ใหม่ ต้อง มี ชื่อ 

ผลอ่ายากนิดนึงแบบ New ({3}) หมายถึงว่า new ตรงกับคำภาษาไทยตัวที่ 3 ใน “รายการ เมนู ใหม่ ต้อง มี ชื่อ” ก็คือใหม่นั่นเอง.

มี 1 ความคิดเห็น »

  1. ขอบคุณมากๆ ค่ะ

    ความเห็น โดย oil — 5 มีนาคม 2008 @ 14:27


RSS feed สำหรับความคิดเห็นในกระทู้นี้ TrackBack URI

เขียนความคิดเห็นของคุณ

บลอกที่ WordPress.com .