Разделить предложение на отдельные слова

мне нужно разделить китайское предложение на отдельные слова. Проблема с китайским заключается в том, что здесь нет пространства. Например, предложение может выглядеть так: 主楼怎么走 (с пробелами это будет:主楼 怎么 走).

на данный момент я могу думать одно решение. У меня есть словарь с китайскими словами (в базе данных). Скрипт:

  1. попробуйте найти первые два символа предложения в базе данных (主楼),

  2. если 主楼 на самом деле это слово, и в базе данных скрипт попытается найти первые три символа (主楼怎). 主楼怎 это не слово, поэтому его нет в базе данных => мое приложение теперь знает, что 主楼 - это отдельное слово.

  3. попробовать сделать это с остальными персонажами.

мне не очень нравится этот подход, потому что для анализа даже небольшого текста он будет запрашивать базу данных слишком много раз.

есть ли другие решения этой проблемы?

11 ответов


спасибо всем за помощь!

после небольшого исследования я нашел некоторые рабочие инструменты (имея в виду все ваши предложения), поэтому я отвечаю на свой вопрос.

  1. класс PHP (http://www.phpclasses.org/browse/package/2431.html)

  2. модуль Drupal, в основном другое решение PHP с 4 различными алгоритмами сегментации (довольно легко понять, как это работает) (http://drupal.org/project/csplitter)

  3. расширение PHP для сегментации китайского слова (http://code.google.com/p/phpcws/)

  4. есть несколько других решений доступно если вы пытаетесь искать baidu.com для "中文分词"

с уважением,

Equ


вы можете рассмотреть возможность использования trie структуры данных. Сначала вы строите trie из словаря, а затем поиск допустимых слов будет намного быстрее. Преимущество определения, если вы находитесь на конце слова или нужно продолжать искать более длинные слова очень быстро.


У вас есть входной текст, предложение, абзац там. Так что да, ваша обработка будет нужно для запроса к вашей БД для каждой проверки.

с приличной индексацией в столбце word, хотя у вас не должно быть слишком много проблем.

сказав это, насколько велик этот словарь? В конце концов, вам понадобятся только слова, а не их определения, чтобы проверить, является ли это действительным словом. Поэтому, если это вообще возможно (в зависимости от размера), имея огромную память карта / hashtable / словарь только с ключами (фактические слова) может быть вариантом и будет быстрым, как молния.

At 15 млн. слова, скажем, в среднем 7 символов @ 2 байт каждый работает вокруг отметки 200 мегабайт. Не слишком сумасшедшая.

Edit: на "только" 1 миллион слов, вы смотрите вокруг чуть более 13 мегабайт, скажем, 15 с некоторыми накладными расходами. Я бы сказал, что это несложно.


еще один, который хорошо работает, это http://www.itgrass.com/phpanalysis/index.html

Это единственный, который я нашел, который работает правильно с utf-8. Остальные работали только для меня в gb18030,что вызвало массу проблем позже. Я думал, что мне придется начать все сначала, но это сэкономило мне много времени.


Ну, если у вас есть база данных со всеми словами, и нет другого способа вовлечь это слово, я думаю, вы вынуждены повторно запросить базу данных.


чтобы улучшить производительность этого, не можете ли вы сделать все эти проверки, прежде чем вставлять предложение в базу данных и добавлять пробелы самостоятельно?


(через ABCDE представлять китайские иероглифы для простоты)

предположим, у вас есть "предложение"ABCDE ввод, и ваш словарь содержит эти слова, которые начинаются с A: AB, ABC, AC, AE и ABB. И предположим, что слово CDE, а DE, nor E нет.

при разборе входных данных предложение, идя слева направо, скрипт вытягивает первый символ A. Вместо того, чтобы запрашивать базу данных, чтобы увидеть, если A это слово, запрос базы данных, чтобы вытащить все слова, которые начинаются с A.

цикл через эти результаты, захватывая следующие несколько символов из входной строки, чтобы получить правильное сравнение:

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

в этот момент программа разветвляется на две "истинные" ветви, которые она нашла. На первом он предполагает AB - Это первое слово, и пытается найти C-начиная слова. CDE найдено, так что ветка возможна. Вниз по другой ветке, ABC - Это первое слово, но DE невозможно, поэтому эта ветвь недействительна, то есть первая должна быть истинной интерпретацией.

Я думаю, что этот метод минимизировал количество вызовов базы данных (хотя он может возвращать большие наборы из базы данных, поскольку вы получаете наборы слов все начинается с одного и того же персонажа). Если бы ваша база данных была индексирована для такого поиска, я думаю, что это будет работать лучше, чем идти буква за буквой. Глядя на весь этот процесс сейчас, и другие ответы, я думаю, что это на самом деле структура trie (предполагая, что искомый персонаж-это корень дерева), как предлагал другой плакат. Ну, вот реализация этой идеи!


Я понимаю, что проблема сегментации китайского слова очень сложна, но в некоторых случаях этого тривиального алгоритма может быть достаточно: найдите самое длинное слово w, начиная с I-го символа, затем начните снова для 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/

Это метод, который я использую в своем Analyzer (duzhe) text Analyzer ( http://duzhe.aaginskiy.com). Я не использую база данных, на самом деле я предварительно загружаю список слов в массив, который занимает около ~2 МБ ОЗУ, но выполняется очень быстро.

Если вы изучаете использование лексической сегментации по статистике (хотя статистический метод может быть таким же точным, как ~97% согласно некоторым исследованиям), очень хорошим инструментом сегментации является ADSOtrans, который можно найти здесь:

http://www.adsotrans.com

Он использует базу данных, но имеет много избыточных таблиц для ускорения до сегментации. Вы также можете предоставить грамматические определения, чтобы помочь сегментации.

надеюсь, что это помогает.


Это довольно стандартная задача в вычислительной лингвистике. Он называется "токенизация" или "сегментация слов"."Попробуйте найти" сегментацию китайского слова" или "китайскую токенизацию", и вы найдете несколько инструментов, которые были сделаны для выполнения этой задачи, а также документы об исследовательских системах для этого.

чтобы сделать это хорошо, вам обычно нужно будет использовать статистическую модель, построенную путем запуска системы машинного обучения на довольно большом учебном корпусе. Несколько системы, которые вы можете найти в интернете, поставляются с предварительно обученными моделями.


вы можете создать очень длинное регулярное выражение.

Edit: Я хотел построить его автоматически с помощью скрипта из БД. Не писать его рука.