我需要将中文句子分为单独的单词。中文的问题是没有空间。例如,该句子看起来像: 主楼怎么走 (在空间中,将是: 主楼 怎么 走).

目前,我可以想到一个解决方案。我有一个带有中文单词的字典(在数据库中)。脚本将:

  1. 尝试在数据库中找到句子的前两个字符(主楼),

  2. 如果 主楼 实际上是一个单词,它在数据库中,脚本将尝试找到前三个字符(主楼怎). 主楼怎 不是一个单词,所以它不在数据库中=>我的应用程序现在知道 主楼 是一个单独的词。

  3. 尝试使用其余角色来做。

我真的不喜欢这种方法,因为即使分析小文本也会查询数据库太多次。

还有其他解决方案吗?

有帮助吗?

解决方案

感谢大家的帮助!

经过一番研究,我发现了一些工作工具(请记住您的所有建议),这就是为什么我要回答自己的问题的原因。

  1. PHP类(http://www.phpclasses.org/browse/package/2431.html)

  2. Drupal模块,基本上是另一种具有4种不同分割算法的PHP解决方案(非常容易理解其工作原理)(http://drupal.org/project/csplitter)

  3. 中文单词细分的PHP扩展(http://code.google.com/p/phpcws/)

  4. 如果您尝试搜索baidu.com以获取“中文分词”,还有其他一些解决方案可用。

真挚地,

其他提示

您可能要考虑使用 特里 数据结构。您首先从字典中构造Trie,然后搜索有效的单词会更快。优势是确定您是否处于单词的末尾或需要继续寻找更长的单词非常快。

您拥有输入文本,句子,段落。是的,您的处理将 需要 查询每张支票的数据库。

但是,随着单词列上的不错的索引,您不应该有太多问题。

话虽如此,这个词典有多大?毕竟,您只需要单词,而不是他们的定义来检查它是否是有效的单词。因此,如果可能的话(取决于尺寸),则使用仅键(实际单词)的巨大内存映射/hashtable/词典可能是一种选择,并且可以很快作为闪电。

1500万 单词,说平均7个字符 @ 2个字节 每个都在200兆字节上算出。不太疯狂。

编辑: 在“只有100万个单词”时,您正在看大约13兆字节,说15个高空上。我会说这是不费吹灰之力的。

另一个运行良好的是 http://www.itgrass.com/phpanalysis/index.html

这是我发现与UTF-8正常工作的唯一一个。其余的只在GB18030中为我工作,这在后来造成了很多问题。我以为我将不得不重新开始,但是这为我节省了很多时间。

好吧,如果您有一个带有所有单词的数据库,并且没有其他方法可以让这些单词涉及,我认为您被迫重新查询数据库。

为了提高此功能,在将句子插入数据库中并自己添加空间之前,您是否可以进行所有这些检查?

(使用 Abcde 代表汉字以简单)

假设您有“句子” Abcde 输入,您的字典包含以下这些单词 一个: ab, ABC, 交流, Ae, , 和 abb. 。并假设这个词 CDE 存在,但是 de, ,也不 e 不要。

解析输入句子时,向左到右,脚本拉了第一个字符 一个. 。而不是查询数据库以查看是否 一个 是一个单词,请查询数据库以拉动所有以开始的单词 一个.

循环通过这些结果,从输入字符串中获取接下来的几个字符,以进行适当的比较:

AB  ?= AB : True
ABC ?= ABC: True
AC  ?= AB : False
AE  ?= AB : False
ABB ?= ABC: False

此时,程序将其划分为它找到的两个“真”分支。首先,它推测 ab 是第一个单词,试图找到 C- 启动单词。 CDE 找到了分支。下一个分支, ABC 是第一个单词,但是 de 是不可能的,因此分支是无效的,这意味着第一个必须是真实的解释。

我认为这种方法最大程度地减少了对数据库的调用数量(尽管它可能会从数据库中返回较大的集合,因为您要获取以同一字符开头的单词集)。如果您的数据库已被索引,我认为这比上字母的字母更好。现在查看整个过程,还有其他答案,我认为这实际上是一个Trie结构(假设搜索的角色是树的根),正如另一位海报所建议的那样。好吧,这是该想法的实现!

我确实意识到中文单词分割问题是一个非常复杂的问题,但是在某些情况下,这种琐碎的算法可能足够:搜索最长的单词w从ith字符开始,然后重新开始以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'),re.compile(r"(?u)^.+? (.+?) .+"))
    text = u"""33. 你可以叫我夏尔
    戴高乐将军和夫人在科隆贝双教堂村过周末。星期日早晨,伊冯娜无意中走进浴室,正巧将军在洗盆浴。她感到非常意外,不禁大叫一声:“我的上帝!”
    戴高乐于是转过身,看见妻子因惊魂未定而站立在门口。他继续用香皂擦身,不紧不慢地说:“伊冯娜,你知道,如果是我们之间的隐私,你可以叫我夏尔,用不着叫我上帝……”
    """
    print cedict.segmentation(text)
    print u" | ".join(cedict.genWords(text))

最后一部分使用了 ccedict词典 将(简化的)中文文本分为两种口味(分别有和没有非字符):

33. 你 | 可以 | 叫 | 我 | 夏 | 尔
    戴高乐 | 将军 | 和 | 夫人 | 在 | 科隆 | 贝 | 双 | 教堂 | 村 | 过 | 周末。星期日 | 早晨,伊 | 冯 | 娜 | 无意中 | 走进 | 浴室,正巧 | 将军 | 在 | 洗 | 盆浴。她 | 感到 | 非常 | 意外,不禁 | 大 | 叫 | 一声:“我的 | 上帝!”
    戴高乐 | 于是 | 转 | 过 | 身,看见 | 妻子 | 因 | 惊魂 | 未定 | 而 | 站立 | 在 | 门口。他 | 继续 | 用 | 香皂 | 擦 | 身,不 | 紧 | 不 | 慢 | 地 | 说:“伊 | 冯 | 娜,你 | 知道,如果 | 是 | 我们 | 之间 | 的 | 隐私,你 | 可以 | 叫 | 我 | 夏 | 尔,用不着 | 叫 | 我 | 上帝……”

你 | 可以 | 叫 | 我 | 夏 | 尔 | 戴高乐 | 将军 | 和 | 夫人 | 在 | 科隆 | 贝 | 双 | 教堂 | 村 | 过 | 周末 | 星期日 | 早晨 | 伊 | 冯 | 娜 | 无意中 | 走进 | 浴室 | 正巧 | 将军 | 在 | 洗 | 盆浴 | 她 | 感到 | 非常 | 意外 | 不禁 | 大 | 叫 | 一声 | 我的 | 上帝 | 戴高乐 | 于是 | 转 | 过 | 身 | 看见 | 妻子 | 因 | 惊魂 | 未定 | 而 | 站立 | 在 | 门口 | 他 | 继续 | 用 | 香皂 | 擦 | 身 | 不 | 紧 | 不 | 慢 | 地 | 说 | 伊 | 冯 | 娜 | 你 | 知道 | 如果 | 是 | 我们 | 之间 | 的 | 隐私 | 你 | 可以 | 叫 | 我 | 夏 | 尔 | 用不着 | 叫 | 我 | 上帝 

一种良好且快速的中文文本方法基于最大匹配分割,这基本上将测试不同的单词长度,以查看哪种分割的组合很可能是可能的。它列出了所有可能的单词的列表。

在这里阅读更多有关它的信息: http://technology.chtsai.org/mmseg/

这就是我在读者(duzhe)文本分析仪中使用的方法( http://duzhe.aaginskiy.com )。我不使用数据库,实际上我将单词列表预先加载到一个数组中,该数组确实占用约2MB的RAM,但执行非常快。

如果您正在考虑对统计学使用词汇分割(尽管根据某些研究的统计方法可以像〜97%一样准确),那么一个非常好的分割工具是AdSotrans,可以在此处找到: http://www.adsotrans.com

它使用数据库,但有很多冗余表来加快细分。您还可以提供语法定义来协助细分。

这是计算语言学中相当标准的任务。它由名称为“ tokenization”或“单词分割”。尝试搜索“中文单词细分”或“中国令牌化”,您会发现几种可以完成此任务的工具,以及有关研究系统的论文。

为了做得很好,您通常需要使用通过在相当大的培训语料库上运行机器学习系统来构建的统计模型。您可以在网络上找到的几个系统都带有预训练的模型。

您可以建立非常长的正则表达方式。

编辑:我的意思是用DB的脚本自动构建它。不要手工写。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top