12

如何从组合字符串中检测和拆分单词?

例子:

"cdimage" -> ["cd", "image"]
"filesaveas" -> ["file", "save", "as"]
4

5 回答 5

11

这是一个动态编程解决方案(作为记忆函数实现)。给定一个带有频率的单词字典,它将输入文本拆分到给出整体最可能短语的位置。你必须找到一个真正的单词表,但我包含了一些虚构的频率以进行简单的测试。

WORD_FREQUENCIES = {
    'file': 0.00123,
    'files': 0.00124,
    'save': 0.002,
    'ave': 0.00001,
    'as': 0.00555
}

def split_text(text, word_frequencies, cache):
    if text in cache:
        return cache[text]
    if not text:
        return 1, []
    best_freq, best_split = 0, []
    for i in xrange(1, len(text) + 1):
        word, remainder = text[:i], text[i:]
        freq = word_frequencies.get(word, None)
        if freq:
            remainder_freq, remainder = split_text(
                    remainder, word_frequencies, cache)
            freq *= remainder_freq
            if freq > best_freq:
                best_freq = freq
                best_split = [word] + remainder
    cache[text] = (best_freq, best_split)
    return cache[text]

print split_text('filesaveas', WORD_FREQUENCIES, {})

--> (1.3653e-08, ['file', 'save', 'as'])
于 2010-02-01T10:45:51.660 回答
8

我不知道它有任何库,但实现基本功能应该不难。

  1. 获取单词列表,例如 UNIX 的words.
  2. 将单词列表的内容塞入 trie 中。
  3. 获取要拆分的字符串并按照其在 trie 中的路径。每次到达有效单词时,创建一个新分支,从您到达的字符串点开始搜索单词。完成当前分支后,回溯到您创建的分支,就像深度优先搜索一样。
  4. 使用启发式或通过自然语言解析器手动消除结果列表的歧义。

例子:

  1. 词:“文件保存字符串”
  2. 第一个有效词是“文件”。尝试匹配“保存”。第一个有效词是“保存”。尝试匹配“asstring”。第一个有效词是“as”。尝试匹配“字符串”。第一个有效单词是“字符串”。匹配到结束;将 [文件另存为字符串] 放入您的结果列表中。
  3. 回溯到匹配的“字符串”——没有其他可能性。回溯到“asstring”。第一个未访问的有效单词是“ass”。尝试匹配“tring”。没有可能的匹配项。回溯到“asstring”。没有可能的匹配项。回溯到“filesaveasstring”。
  4. 第一个未访问的匹配是“文件”。尝试匹配“aveasstring”。第一场比赛是“ave”。尝试匹配“asstring”(与步骤 2/3 的结果相同),将 [files ave as string] 添加到您的结果列表并回溯到开始。
  5. 尝试匹配“filesaveasstring”。没有未观看的比赛。完毕。
  6. 使用启发式或自然语言解析器从 [[file save as string] [files ave as string]] 中选择最有可能的。
于 2010-02-01T01:17:11.807 回答
2

我不知道有这样的库,但如果你有一个单词列表,写起来并不难:

wordList = file('words.txt','r').read().split()
words = set( s.lower() for s in wordList )

def splitString(s):
    found = []

    def rec(stringLeft, wordsSoFar):
        if not stringLeft:
            found.append(wordsSoFar)
        for pos in xrange(1, len(stringLeft)+1):
            if stringLeft[:pos] in words:
                rec(stringLeft[pos:], wordsSoFar + [stringLeft[:pos]])

    rec(s.lower(), [])
    return found

这将返回将字符串拆分为给定单词的所有可能方式。

例子:

>>> splitString('filesaveas')
[['file', 'save', 'as'], ['files', 'ave', 'as']]
于 2010-02-01T01:17:38.477 回答
0

可以看到这个例子:但它是用scala写的。当句子之间没有空格时,这可以拆分您想要的任何内容。

非间隔句分词器

于 2020-08-16T11:05:39.067 回答
-2

我知道这个问题是针对 Python 标记的,但我需要一个 JavaScript 实现。离开以前的答案,我想我会分享我的代码。似乎工作得体。

function findWords(input){
    input = input.toLowerCase().replace(/\s/g, ""); //Strip whitespace

    var index = 0;
    var validWords = [];
    for (var len = input.length; len > 0; len--){ //Go backwards as to favor longer words
        var testWord = input.substr(index, len);
        var dictIndex = _dictionary.indexOf(testWord.replace(/[^a-z\']/g, "")); //Remove non-letters
        if (dictIndex != -1){
            validWords.push(testWord);
            if (len == input.length){
                break; //We are complete
            }
            var nextWords = findWords(input.substr(len, input.length - len)); //Recurse
            if (!nextWords.words.length){ //No further valid words
                validWords.pop();
            }
            validWords = validWords.concat(nextWords.words);
            if (nextWords.complete === true){
                break; //Cascade complete
            }
        }
    }
    return {
        complete:len > 0, //We broke which indicates completion
        words:validWords
    };
}

注意:“_dictionary”应该是一个按频率排序的单词数组。我正在使用 Project Gutenberg 的词汇表。

于 2017-08-28T00:13:21.827 回答