Pergunta

Preciso dividir uma frase chinesa em palavras separadas. O problema com o chinês é que não há espaços. Por exemplo, a frase pode parecer: 主楼怎么走 (Com espaços, seria: 主楼 怎么 走).

No momento, consigo pensar em uma solução. Eu tenho um dicionário com palavras chinesas (em um banco de dados). O script irá:

  1. Tente encontrar os dois primeiros caracteres da frase no banco de dados (主楼),

  2. E se 主楼 é realmente uma palavra e está no banco de dados, o script tentará encontrar os três primeiros caracteres (主楼怎). 主楼怎 não é uma palavra, então não está no banco de dados => meu aplicativo agora sabe que 主楼 é uma palavra separada.

  3. Tente fazer isso com o resto dos personagens.

Eu realmente não gosto dessa abordagem, porque para analisar mesmo um texto pequeno, ele consultaria o banco de dados muitas vezes.

Existem outras soluções para isso?

Foi útil?

Solução

Obrigado a todos por sua ajuda!

Depois de uma pequena pesquisa, encontrei algumas ferramentas de trabalho (tendo em mente todas as suas sugestões), é por isso que estou respondendo à minha própria pergunta.

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

  2. Um módulo Drupal, basicamente outra solução PHP com 4 algoritmos de segmentação diferentes (muito fácil de entender como funciona) (http://drupal.org/project/csplitter)

  3. Uma extensão PHP para segmentação de palavras chinesas (http://code.google.com/p/phpcws/)

  4. Existem outras soluções disponíveis se você tentar pesquisar baidu.com por "中文 分词"

Sinceramente,

Equ

Outras dicas

Você pode querer considerar usar um Trie estrutura de dados. Primeiro você constrói o trie do dicionário e pesquisar palavras válidas será muito mais rápido. A vantagem é determinar se você está no final de uma palavra ou precisa continuar procurando palavras mais longas é muito rápido.

Você tem o texto de entrada, frase, parágrafo. Então, sim, o seu processamento disso precisar Para consultar o seu banco de dados para cada cheque.

Com indexação decente na coluna da palavra, você não deve ter muitos problemas.

Dito isto, quão grande é esse dicionário? Afinal, você precisaria apenas das palavras, não de suas definições para verificar se é uma palavra válida. Portanto, se possível (dependendo do tamanho), ter um enorme mapa de memória/hashtable/dicionário com apenas teclas (as palavras reais) pode ser uma opção e seria rápido como um raio.

No 15 milhões Palavras, diga em média 7 caracteres @ 2 bytes Cada um funciona em torno da marca de 200 megabytes. Não é muito louco.

Editar: Com 'apenas 1 milhão de palavras, você está olhando para pouco mais de 13 megabytes, digamos 15 com algumas notas aéreas. Isso é um acéfalo, eu diria.

Outro que funciona bem é http://www.itgrass.com/phpanalysis/index.html

É o único que eu encontrei que funciona corretamente com o UTF-8. O resto funcionou apenas para mim no GB18030, o que causou toneladas de questões posteriormente. Eu pensei que teria que começar de novo, mas este me salvou muito tempo.

Bem, se você tiver um banco de dados com todas as palavras e não há outra maneira de envolver essas palavras, acho que você é forçado a re-interpar o banco de dados.

Para melhorar o desempenho disso, você não pode fazer todas essas verificações antes de inserir a frase no banco de dados e adicionar espaços?

(usando ABCDE para representar caracteres chineses por simplicidade)

Digamos que você tenha a 'frase' ABCDE entrada, e seu dicionário contém essas palavras que começam com UMA: Ab, abc, AC, Ae, e ABB. E presumir que a palavra CDE existe, mas De, nem E não faça.

Ao analisar a frase de entrada, indo para a esquerda para a direita, o script puxa o primeiro caractere UMA. Em vez de consultar o banco de dados para ver se UMA é uma palavra, consulte o banco de dados para puxar todas as palavras que começam com UMA.

Faça um loop nesses resultados, pegando os próximos caracteres da string de entrada para obter uma comparação adequada:

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

Neste ponto, o programa bate nos dois ramos 'verdadeiros' que encontrou. No primeiro, presume Ab é a primeira palavra e tenta encontrar C-Palavras iniciantes. CDE é encontrado, para que o ramo seja possível. No outro ramo, abc é a primeira palavra, mas De não é possível, de modo que o ramo é inválido, o que significa que o primeiro deve ser a verdadeira interpretação.

Eu acho que esse método minimizou o número de chamadas para o banco de dados (embora possa retornar conjuntos maiores do banco de dados, pois você está buscando conjuntos de palavras começando com o mesmo caractere). Se o seu banco de dados fosse indexado para esse tipo de pesquisa, acho que isso funcionaria melhor do que a carta por carta a by. Olhando para todo esse processo agora, e as outras respostas, acho que essa é realmente uma estrutura de trie (assumindo que o personagem pesquisado é a raiz de uma árvore), como outro pôster havia sugerido. Bem, aqui está uma implementação dessa ideia!

Percebo que o problema de segmentação de palavras chinês é muito complexo, mas em alguns casos esse algoritmo trivial pode ser suficiente: procure a palavra mais longa w começando com o caráter é .

Aqui está uma implementação do 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))

A última parte usa uma cópia do CCEDICT DICIONÁRIO para segmentar um texto chinês (simplificado) em dois sabores (resp., com e sem caracteres não palavras):

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

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

Uma maneira boa e rápida de segmentar o texto chinês é baseado na segmentação máxima de correspondência, que basicamente testará diferentes palavras para ver qual combinação de segmentação é mais provável. É preciso uma lista de todas as palavras possíveis para fazê -lo.

Leia mais sobre isso aqui: http://technology.chtsai.org/mmseg/

Esse é o método que eu uso no meu analisador de texto 读者 (Duzhe) ( http://duzhe.aaginskiy.com ). Não uso um banco de dados, na verdade, pré-carrego uma lista de palavras em uma matriz que leva cerca de ~ 2 MB de RAM, mas é executada muito rapidamente.

Se você está investigando o uso da segmentação lexical sobre estatística (embora o método estatístico possa ser tão preciso quanto ~ 97% de acordo com algumas pesquisas), uma ferramenta de segmentação muito boa são adsotrans que podem ser encontrados aqui: http://www.adsotrans.com

Ele usa um banco de dados, mas possui muitas tabelas redundantes para acelerar a segmentação. Você também pode fornecer definições gramaticais para ajudar a segmentação.

Esta é uma tarefa bastante padrão na linguística computacional. Ele passa pelo nome "tokenização" ou "segmentação de palavras". Tente procurar "segmentação de palavras chinesas" ou "tokenização chinesa" e você encontrará várias ferramentas que foram feitas para realizar essa tarefa, além de artigos sobre sistemas de pesquisa para fazê -lo.

Para fazer isso bem, você normalmente precisará usar um modelo estatístico construído executando um sistema de aprendizado de máquina em um corpus de treinamento bastante grande. Vários dos sistemas que você pode encontrar na Web vêm com modelos pré-treinados.

Você pode construir uma expressão regular muito longa.

Editar:Eu pretendia construí -lo automaticamente com o script a partir do banco de dados. Para não escrever à mão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top