Skip to content

Commit aa80273

Browse files
committed
precompile pattern/regex that use frequently (PAT_ENG, PAT_TCC, PAT_TWOCHARS)
1 parent e28c46e commit aa80273

File tree

1 file changed

+83
-64
lines changed

1 file changed

+83
-64
lines changed

pythainlp/tokenize/newmm.py

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
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
67
https://colab.research.google.com/drive/14Ibg-ngZXj15RKwjNwoZlOT32fQBOrBx#scrollTo=MYZ7NzAR7Dmw
7-
'''
8+
"""
89
from __future__ import absolute_import, unicode_literals
10+
911
import re
1012
from collections import defaultdict
11-
from heapq import heappush, heappop # for priority queue
13+
from heapq import heappop, heappush # for priority queue
14+
1215
from 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ยะ
@@ -44,19 +51,26 @@
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

5065
def 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+
7186
def 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

8197
def 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+
# ช่วยให้ไม่ต้องพิมพ์ยาวๆ
130149
def mmcut(text, trie=None):
131150
if not trie:
132151
trie = DEFAULT_DICT_TRIE

0 commit comments

Comments
 (0)