11# -*- coding: utf-8 -*-
22
3- ''' ตัวตัดคำภาษาไทยโดยใช้หลักการ maximal matching และ TCC
3+ """ ตัวตัดคำภาษาไทยโดยใช้หลักการ maximal matching และ TCC
44พัฒนาโดยคุณ Korakot Chaovavanich
5- Notebook : https://colab.research.google.com/notebook#fileId=1V1Z657_5eSWPo8rLfVRwA0A5E4vkg7SI
5+ Notebooks:
6+ https://colab.research.google.com/notebook#fileId=1V1Z657_5eSWPo8rLfVRwA0A5E4vkg7SI
67https://colab.research.google.com/drive/14Ibg-ngZXj15RKwjNwoZlOT32fQBOrBx#scrollTo=MYZ7NzAR7Dmw
7- '''
8+ """
89from __future__ import absolute_import , unicode_literals
10+
911import re
1012from collections import defaultdict
11- from heapq import heappush , heappop # for priority queue
13+ from heapq import heappop , heappush # for priority queue
14+
1215from pythainlp .tokenize import DEFAULT_DICT_TRIE
1316
1417# ช่วยตัดพวกภาษาอังกฤษ เป็นต้น
15- pat_eng = re .compile (r'''(?x)
18+ PAT_ENG = re .compile (
19+ r"""(?x)
1620[-a-zA-Z]+| # english
1721\d[\d,\.]*| # number
1822[ \t]+| # space
1923\r?\n # newline
20- ''' )
24+ """
25+ )
26+
2127# TCC
22- pat_tcc = """\
28+ re_tcc = (
29+ """\
2330 เc็c
2431เcctาะ
2532เccีtยะ
4451แccc์
4552โctะ
4653[เ-ไ]ct
47- """ .replace ('c' , '[ก-ฮ]' ).replace ('t' , '[่-๋]?' ).split ()
54+ """ .replace (
55+ "c" , "[ก-ฮ]"
56+ )
57+ .replace ("t" , "[่-๋]?" )
58+ .split ()
59+ )
60+
61+ PAT_TCC = re .compile ("|" .join (re_tcc ))
62+ PAT_TWOCHARS = re .compile ("[ก-ฮ]{,2}$" )
4863
4964
5065def tcc (w ):
5166 p = 0
52- pat = re .compile ("|" .join (pat_tcc ))
5367 while p < len (w ):
54- m = pat .match (w [p :])
68+ m = PAT_TCC .match (w [p :])
5569 if m :
5670 n = m .span ()[1 ]
5771 else :
5872 n = 1
59- yield w [p : p + n ]
73+ yield w [p : p + n ]
6074 p += n
6175
6276
@@ -68,65 +82,70 @@ def tcc_pos(text):
6882 p_set .add (p )
6983 return p_set
7084
85+
7186def bfs_paths_graph (graph , start , goal ):
72- queue = [(start , [start ])]
73- while queue :
74- (vertex , path ) = queue .pop (0 )
75- for next in graph [vertex ]:
76- if next == goal :
77- yield path + [next ]
78- else :
79- queue .append ((next , path + [next ]))
87+ queue = [(start , [start ])]
88+ while queue :
89+ (vertex , path ) = queue .pop (0 )
90+ for next in graph [vertex ]:
91+ if next == goal :
92+ yield path + [next ]
93+ else :
94+ queue .append ((next , path + [next ]))
95+
8096
8197def onecut (text , trie ):
82- graph = defaultdict (list ) # main data structure
83- allow_pos = tcc_pos (text ) # ตำแหน่งที่ตัด ต้องตรงกับ tcc
84-
85- q = [0 ] # min-heap queue
86- last_p = 0 # last position for yield
87- while q [0 ] < len (text ):
88- p = heappop (q )
89-
90- for w in trie .prefixes (text [p :]):
91- p_ = p + len (w )
92- if p_ in allow_pos : # เลือกที่สอดคล้อง tcc
93- graph [p ].append (p_ )
94- if p_ not in q :
95- heappush (q , p_ )
96-
97- # กรณี length 1 คือ ไม่กำกวมแล้ว ส่งผลลัพธ์ก่อนนี้คืนได้
98- if len (q )== 1 :
99- pp = next (bfs_paths_graph (graph , last_p , q [0 ]))
100- # เริ่มต้น last_p = pp[0] เอง
101- for p in pp [1 :]:
102- yield text [last_p :p ]
103- last_p = p
104- # สุดท้าย last_p == q[0] เอง
105-
106- # กรณี length 0 คือ ไม่มีใน dict
107- if len (q )== 0 :
108- m = pat_eng .match (text [p :])
109- if m : # อังกฤษ, เลข, ว่าง
110- i = p + m .end ()
111- else : # skip น้อยที่สุด ที่เป็นไปได้
112- for i in range (p + 1 , len (text )):
113- if i in allow_pos : # ใช้ tcc ด้วย
114- ww = [w for w in trie .prefixes (text [i :]) if (i + len (w ) in allow_pos )]
115- ww = [w for w in ww if not re .match ('[ก-ฮ]{,2}$' , w )]
116- m = pat_eng .match (text [i :])
117- if ww or m :
118- break
119- else :
120- i = len (text )
121- w = text [p :i ]
122- graph [p ].append (i )
123- yield w
124- last_p = i
125- heappush (q , i )
98+ graph = defaultdict (list ) # main data structure
99+ allow_pos = tcc_pos (text ) # ตำแหน่งที่ตัด ต้องตรงกับ tcc
126100
127- # ช่วยให้ไม่ต้องพิมพ์ยาวๆ
101+ q = [0 ] # min-heap queue
102+ last_p = 0 # last position for yield
103+ while q [0 ] < len (text ):
104+ p = heappop (q )
105+
106+ for w in trie .prefixes (text [p :]):
107+ p_ = p + len (w )
108+ if p_ in allow_pos : # เลือกที่สอดคล้อง tcc
109+ graph [p ].append (p_ )
110+ if p_ not in q :
111+ heappush (q , p_ )
112+
113+ # กรณี length 1 คือ ไม่กำกวมแล้ว ส่งผลลัพธ์ก่อนนี้คืนได้
114+ if len (q ) == 1 :
115+ pp = next (bfs_paths_graph (graph , last_p , q [0 ]))
116+ # เริ่มต้น last_p = pp[0] เอง
117+ for p in pp [1 :]:
118+ yield text [last_p :p ]
119+ last_p = p
120+ # สุดท้าย last_p == q[0] เอง
128121
122+ # กรณี length 0 คือ ไม่มีใน dict
123+ if len (q ) == 0 :
124+ m = PAT_ENG .match (text [p :])
125+ if m : # อังกฤษ, เลข, ว่าง
126+ i = p + m .end ()
127+ else : # skip น้อยที่สุด ที่เป็นไปได้
128+ for i in range (p + 1 , len (text )):
129+ if i in allow_pos : # ใช้ tcc ด้วย
130+ ww = [
131+ w
132+ for w in trie .prefixes (text [i :])
133+ if (i + len (w ) in allow_pos )
134+ ]
135+ ww = [w for w in ww if not PAT_TWOCHARS .match (w )]
136+ m = PAT_ENG .match (text [i :])
137+ if ww or m :
138+ break
139+ else :
140+ i = len (text )
141+ w = text [p :i ]
142+ graph [p ].append (i )
143+ yield w
144+ last_p = i
145+ heappush (q , i )
129146
147+
148+ # ช่วยให้ไม่ต้องพิมพ์ยาวๆ
130149def mmcut (text , trie = None ):
131150 if not trie :
132151 trie = DEFAULT_DICT_TRIE
0 commit comments