php拆词,关于php:将句⼦拆分成单独的单词
我需要将中⽂句⼦拆分为单独的单词。 中⽂的问题是没有空格。 例如,该句⼦可能看起来像:主楼怎么⾛(带空格的地⽅是:主楼 怎么⾛)。
⽬前,我可以想到⼀种解决⽅案。 我有⼀本有中⽂单词的字典(在数据库中)。 该脚本将:
尝试在数据库中到句⼦的前两个字符(主楼),
如果主楼实际上是⼀个单词,并且在数据库中,脚本将尝试查前三个字符(主楼怎)。 主楼怎不是单词,所以不在数据库中=>我的应⽤程序现在知道主楼是⼀个单独的单词。
尝试⽤其余的⾓⾊来做。
我不太喜欢这种⽅法,因为即使分析很⼩的⽂本,它也会查询数据库太多次。
正则表达式提取中文字符还有其他解决⽅案吗?
很好奇,如果中⽂没有空格,为什么需要(⼤概)⽤空格显⽰? 这⾥的⽤例是什么? 嗯-对不起,再读⼀遍问题,显然是⼀些单词字典查,没关系。
补充⼀下Wim所说的,如果只是为了换⾏,就不要打扰:据我所知,您可以将⾏换成任何字符。
该应⽤程序需要到单独的单词,并为他们提供拼⾳(中⽂转录)。
您是否在每个字母之后查询数据库? 还是仅针对单词中的第⼀个字母?
如果前两个字符是单词,前三个字符是单词,第三个字符本⾝是单词,那么您如何知道要使⽤哪个?
好吧,它不⼀定是完美的,⽽实际上它不是完美的,它是机器翻译,⽽不是⼈类=)
感谢⼤家的帮助!
经过⼀番研究,我发现了⼀些⼯作⼯具(牢记您的所有建议),这就是为什么我要回答⾃⼰的问题。
⼀个PHP类(/browse/package/2431.html)
⼀个Drupal模块,基本上是另⼀个具有4种不同细分算法的PHP解决⽅案(⾮常容易理解它的⼯作原理)
(/project/csplitter)
⽤于中⽂分词的PHP扩展(le/p/phpcws/)
如果您尝试在baidu上搜索"中⽂分词",则还有其他解决⽅案
真诚的
qu
您可能要考虑使⽤trie数据结构。您⾸先要从字典中构造特⾥,然后搜索有效的单词会更快。好处是可以很快地确定您是单词的结尾还是需要继续寻更长的单词。
它也可以实现为正则表达式(您知道:⾃动机,有限状态机,规则语⾔等)。编译后,⼤多数正则表达式实现将构建种类。
@Y。肖翰(Shoham):有⼈说正则表达式让你早上⼲杯。
另⼀个效果很好的⽅法是www.itgrass/phpanalysis/index.html
这是我发现的唯⼀可以与utf-8⼀起使⽤的软件。其余的仅在gb18030中为我⼯作,后来导致⼤量问题。我以为我必须重新开始,但这⼀次节省了我很多时间。
您可以输⼊任何⽂本,句⼦,段落。所以是的,您的处理将需要针对每个检查针对您的数据库查询。
尽管在word列上有了不错的索引,您应该不会有太多问题。
话虽这么说,这本词典有多⼤?毕竟,您只需要单词⽽不是它们的定义来检查它是否有效。因此,如果有可能(取决于⼤⼩),可以选择仅具有键(实际单词)的巨⼤内存映射/哈希表/字典,这将是⼀种选择,并且会像闪电般迅速。
在1500万个单词的情况下,说平均7个字符@ 2个字节,每个单词⼤约算出200兆字节。不太疯狂。
编辑:"仅"⼀百万个单词,您所看到的⼤约只有13兆字节,⽐如说有⼀些开销的15兆字节。我会说的很容易。
⽬前只有30万个字,最多只能有100万个字。所以我想这是⼀个选择=)
在那种情况下,我肯定会将所有单词扔到内存中的字典对象中。
分割中⽂⽂本的⼀种好⽅法是基于最⼤匹配分割法,该⽅法基本上可以测试不同长度的单词,以查看哪种分割法最有可能。它包含所有可能的单词的列表。
在此处了解更多信息:/mmseg/
这就是我在读者(DuZhe)⽂本分析器(duzhe.aaginskiy)中使⽤的⽅法。我不使⽤数据库,实际上我将单词列表预加载到⼀个数组中,该数组确实占⽤约2MB的RAM,但是执⾏速度⾮常快。
如果您正在研究在统计上使⽤词法分段(尽管根据某些研究统计⽅法可以达到约97%的准确度),那么⾮常好的分段⼯具是ADSOtrans,可以在以下⽹址到:www.adsotrans
它使⽤数据库,但具有许多冗余表以加快分段速度。您还可以提供语法定义来辅助分割。
我确实意识到中⽂分词问题是⼀个⾮常复杂的问题,但是在某些情况下,这种琐碎的算法可能就⾜够了:搜索从第ith个字符开始的最长单词w,然后再次搜索第i + length(w)个字符。
这是⼀个Python实现:
#!/usr/bin/env python# encoding: utf-8
import re
import unicodedata
import codecs
class ChineseDict:
def __init__(self,lines,rex):
self.words = set(rex.match(line).group(1) for line in lines if not line.startswith("#"))
self.maxWordLength = max(map(len,self.words))
def segmentation(self,text):
result = []
previousIsSticky = False
i = 0
while i < len(text):
for j in range(i+self.maxWordLength,i,-1):
s = text[i:j]
if s in self.words:
break
sticky = len(s)==1 and unicodedata.category(s)!="Lo"
if previousIsSticky or (result and sticky):
result[-1] += s
else:
result.append(s)
previousIsSticky = sticky
i = j
return u" |".join(result)
def genWords(self,text):
i = 0
while i < len(text):
for j in range(i+self.maxWordLength,i,-1):
s = text[i:j]
if s in self.words:
yield s
break
i = j
if __name__=="__main__":
cedict = ChineseDict(codecs.open("cedict_ts.u8",'r','utf-8'),repile(r"(?u)^.+? (.+?) .+"))
text = u"""33. 你可以叫我夏尔
戴⾼乐将军和夫⼈在科隆贝双教堂村过周末。星期⽇早晨,伊冯娜⽆意中⾛进浴室,正巧将军在洗盆浴。她感到⾮常意外,不禁⼤叫⼀声:"我的上帝!"
戴⾼乐于是转过⾝,看见妻⼦因惊魂未定⽽站⽴在门⼝。他继续⽤⾹皂擦⾝,不紧不慢地说:"伊冯娜,你知道,如果是我们之间的隐私,你可以叫我夏尔,⽤不着叫我上帝……"
"""
print cedict.segmentation(text)
print u" |".Words(text))
最后⼀部分使⽤CCEDICT词典的副本将(简体)中⽂⽂本分为两种形式(分别带有和不带有⾮单词字符):
33. 你 | 可以 | 叫 | 我 | 夏 | 尔
戴⾼乐 | 将军 | 和 | 夫⼈ | 在 | 科隆 | 贝 | 双 | 教堂 | 村 | 过 | 周末。星期⽇ | 早晨,伊 | 冯 | 娜 | ⽆意中 | ⾛进 | 浴室,正巧 | 将军 | 在| 洗 | 盆浴。她 | 感到 | ⾮常 | 意外,不禁 | ⼤ | 叫 | ⼀声:"我的 | 上帝!"
戴⾼乐 | 于是 | 转 | 过 | ⾝,看见 | 妻⼦ | 因 | 惊魂 | 未定 | ⽽ | 站⽴ | 在 | 门⼝。他 | 继续 | ⽤ | ⾹皂 | 擦 | ⾝,不 | 紧 | 不 | 慢 | 地 |说:"伊 | 冯 | 娜,你 | 知道,如果 | 是 | 我们 | 之间 | 的 | 隐私,你 | 可以 | 叫 | 我 | 夏 | 尔,⽤不着 | 叫 | 我 | 上帝……"
你 | 可以 | 叫 | 我 | 夏 | 尔 | 戴⾼乐 | 将军 | 和 | 夫⼈ | 在 | 科隆 | 贝 | 双 | 教堂 | 村 | 过 | 周末 | 星期⽇ | 早晨 | 伊 | 冯 | 娜 | ⽆意中 |⾛进 | 浴室 | 正巧 | 将军 | 在 | 洗 | 盆浴 | 她 | 感到 | ⾮常 | 意外 | 不禁 | ⼤ | 叫 | ⼀声 | 我的 | 上帝 | 戴⾼乐 | 于是 | 转 | 过 | ⾝ | 看见| 妻⼦ | 因 | 惊魂 | 未定 | ⽽ | 站⽴ | 在 | 门⼝ | 他 | 继续 | ⽤ | ⾹皂 | 擦 | ⾝ | 不 | 紧 | 不 | 慢 | 地 | 说 | 伊 | 冯 | 娜 | 你 | 知道 | 如果| 是 | 我们 | 之间 | 的 | 隐私 | 你 | 可以 | 叫 | 我 | 夏 | 尔 | ⽤不着 | 叫 | 我 | 上帝
(为简单起见,使⽤ABCDE表⽰汉字)
假设您有"句⼦" ABCDE输⼊,并且您的词典中包含以下以A开头的单词:AB,ABC,AC,AE和ABB。并且假定单词CDE存在,但是DE 或E不存在。
在解析输⼊语句时,脚本从左到右,提取第⼀个字符A。与其查询数据库以查看A是否为单词,不如查询数据库以提取所有以A开头的单词。
遍历这些结果,从输⼊字符串中获取接下来的⼏个字符以进⾏适当的⽐较:
AB ?= AB : True
ABC ?= ABC: True
AC ?= AB : False
AE ?= AB : False
ABB ?= ABC: False
此时,程序会分叉它到的两个"真实"分⽀。⾸先,它假定AB是第⼀个单词,并尝试查C开头的单词。到了CDE,因此可以进⾏分⽀。在另⼀个分⽀下,ABC是第⼀个单词,但是DE不可能,因此该分⽀⽆效,这意味着第⼀个必须是真实的解释。
我认为这种⽅法可以最⼤程度地减少对数据库的调⽤次数(尽管它可能会从数据库中返回更⼤的集合,因为您正在获取所有以相同字符开头的词组)。如果您的数据库被索引⽤于这种搜索,那么我认为这样做会⽐逐字逐句更好。现在看⼀下整个过程以及其他答案,我认为这实际上是⼀个特⾥结构(假定所搜索的⾓⾊是⼀棵树的根),正如另⼀位海报所暗⽰的那样。好吧,这是该想法的实现!
为了提⾼此性能,您是否可以在将句⼦插⼊数据库并⾃⼰添加空格之前进⾏所有这些检查?
问题似乎在于检查时,您需要查询字典...只是为了知道在哪⾥分句。
不幸的是,这应该由应⽤程序⾃动完成。⽤户输⼊句⼦并⽤拼⾳得到单独的单词。
好吧,如果您有⼀个包含所有单词的数据库,并且没有其他⽅法可以使这些单词参与其中,那么我认为您被迫重新查询数据库。
这是计算语⾔学中相当标准的任务。它的名称为"令牌化"或"分词"。尝试搜索"中⽂分词"或"中⽂标记化",您会发现已完成此任务的⼏种⼯具以及有关实现此⽬的的研究系统的论⽂。
为了做到这⼀点,您通常需要使⽤通过在相当⼤的训练语料库上运⾏机器学习系统⽽构建的统计模型。在⽹络上可以到的⼀些系统都带有预训练的模型。
您可以构建⾮常长的正则表达式。
编辑:
我的意思是使⽤数据库中的脚本⾃动构建它。不写
⼿。
您认为正则表达式将如何过滤完整的字典?
@Younes:⾮常⾮常长? ...⼜丑
⽤正则表达式解决这个问题是胡说⼋道
@Eineki:编译后,正如Vincent Ramdhanie所建议的那样,⼤多数正则表达式实现都将构建三重⾃动机。
@Bedwyr:那就是我的意思;)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论