Programing

공백이없는 텍스트를 단어 목록으로 분할하는 방법은 무엇입니까?

lottogame 2020. 9. 6. 11:51
반응형

공백이없는 텍스트를 단어 목록으로 분할하는 방법은 무엇입니까?


입력 : "tableapplechairtablecupboard..." 많은 단어

이러한 텍스트를 단어 목록으로 분할하고 다음을 얻는 효율적인 알고리즘은 무엇입니까?

산출: ["table", "apple", "chair", "table", ["cupboard", ["cup", "board"]], ...]

가장 먼저 떠오르는 것은 가능한 모든 단어 (첫 글자로 시작)를 살펴보고 가능한 가장 긴 단어를 찾고 position=word_position+len(word)

추신 :
가능한 모든 단어 목록이 있습니다.
단어 "찬장"은 "컵"과 "보드"가 될 수 있으며 가장 긴 것을 선택하십시오.
언어 : 파이썬,하지만 중요한 것은 알고리즘 자체입니다.


순진한 알고리즘은 실제 데이터에 적용될 때 좋은 결과를 제공하지 않습니다. 다음은 실제 단어 텍스트에 대한 정확한 결과를 제공하기 위해 상대 단어 빈도를 이용하는 20 줄 알고리즘입니다.

(단어 빈도를 사용하지 않는 원래 질문에 대한 답을 원하면 "가장 긴 단어"가 정확히 무엇을 의미하는지 수정해야합니다. 20 자 단어와 10 자 3 자 단어를 갖는 것이 더 낫습니까? 10 자 단어 5 개가 더 좋은가요? 정확한 정의를 정했다면 wordcost의도 한 의미를 반영하도록 정의하는 줄을 변경하면됩니다 .)

아이디어

진행하는 가장 좋은 방법 은 출력 분포 모델링 하는 것입니다. 첫 번째 근사치는 모든 단어가 독립적으로 분포되어 있다고 가정하는 것입니다. 그러면 모든 단어의 상대적 빈도 만 알면됩니다. 그들이 Zipf의 법칙을 따른다고 가정하는 것이 합리적 입니다. 즉, 단어 목록에서 순위가 n 인 단어의 확률은 대략 1 / ( n log N )이고 여기서 N 은 사전의 단어 수입니다.

모델을 수정 한 후에는 동적 프로그래밍을 사용하여 공간의 위치를 ​​추론 할 수 있습니다. 가장 가능성이 높은 문장은 각 개별 단어의 확률의 곱을 최대화하는 문장이며 동적 프로그래밍으로 계산하기 쉽습니다. 확률을 직접 사용하는 대신 오버플로를 방지하기 위해 확률의 역 로그로 정의 된 비용을 사용합니다.

코드

from math import log

# Build a cost dictionary, assuming Zipf's law and cost = -math.log(probability).
words = open("words-by-frequency.txt").read().split()
wordcost = dict((k, log((i+1)*log(len(words)))) for i,k in enumerate(words))
maxword = max(len(x) for x in words)

def infer_spaces(s):
    """Uses dynamic programming to infer the location of spaces in a string
    without spaces."""

    # Find the best match for the i first characters, assuming cost has
    # been built for the i-1 first characters.
    # Returns a pair (match_cost, match_length).
    def best_match(i):
        candidates = enumerate(reversed(cost[max(0, i-maxword):i]))
        return min((c + wordcost.get(s[i-k-1:i], 9e999), k+1) for k,c in candidates)

    # Build the cost array.
    cost = [0]
    for i in range(1,len(s)+1):
        c,k = best_match(i)
        cost.append(c)

    # Backtrack to recover the minimal-cost string.
    out = []
    i = len(s)
    while i>0:
        c,k = best_match(i)
        assert c == cost[i]
        out.append(s[i-k:i])
        i -= k

    return " ".join(reversed(out))

함께 사용할 수있는

s = 'thumbgreenappleactiveassignmentweeklymetaphor'
print(infer_spaces(s))

결과

나는 Wikipedia의 작은 부분 집합에서 모아 놓은이 빠르고 더러운 125k 단어 사전 을 사용하고 있습니다.

이전 : thumbgreenappleactiveassignmentweeklymetaphor.
이후 : 엄지 녹색 사과 활성 할당 주간 은유.

이전 : html에서 파싱 된 사람들의 의견에 대한 소프트 확장 정보가 있습니다 . 그러나 예를 들어 엄지 그린 애플 활성 할당 주간 메타포 rapparentlytherearethumbgreenappleetc.

이후 : html에서 파싱 된 사람들의 댓글에 대한 텍스트 정보가 많지만 그 안에 구분 된 문자가 없습니다. 예를 들어 thumb green apple 활성 할당 주간 은유 분명히 문자열에 thumb green apple 등이 있습니다. 단어가 합리적인지 쿼리하여 가장 빠른 추출 방법은 무엇입니까?

이전 : 어둡고 폭풍이 몰아 치는 밤하늘을 타는 급류는 격렬한 바람에 의해 거리를 휩쓸었던 런던의 거리를 휩쓸었던 간헐적 인 간격을 제외하고는 우리의 풍경이 집 꼭대기를 따라 울부 짖으며 어두움에 맞서 투쟁하는 등불을 휘젓고있었습니다.

그 후 : 어둡고 폭풍우가 치는 밤이었는데, 거리를 휩쓸었던 격렬한 돌풍에 의해 가끔씩 비가 급류로 떨어졌습니다. 우리 장면이 집 꼭대기를 따라 덜거덕 거리며 격렬하게 선동하는 런던에 있기 때문입니다. 어둠에 맞서 싸운 램프의 희미한 불꽃.

보시다시피 본질적으로 완벽합니다. 가장 중요한 부분은 단어 목록이 실제로 만나게 될 것과 유사한 말뭉치로 훈련되었는지 확인하는 것입니다. 그렇지 않으면 결과가 매우 나빠질 것입니다.


최적화

구현은 선형적인 시간과 메모리를 사용하므로 상당히 효율적입니다. 추가 속도 향상이 필요한 경우 단어 목록에서 접미사 트리를 만들어 후보자 집합의 크기를 줄일 수 있습니다.

매우 큰 연속 문자열을 처리해야하는 경우 과도한 메모리 사용을 방지하기 위해 문자열을 분할하는 것이 합리적입니다. 예를 들어 경계 효과를 피하기 위해 텍스트를 10000 자 블록과 양쪽에 1000 자 여백으로 처리 할 수 ​​있습니다. 이것은 메모리 사용량을 최소로 유지하고 품질에 거의 영향을 미치지 않습니다.


상위 답변 의 우수한 작업을 기반으로 pip사용하기 쉬운 패키지를 만들었습니다 .

>>> import wordninja
>>> wordninja.split('derekanderson')
['derek', 'anderson']

설치하려면 pip install wordninja.

유일한 차이점은 사소합니다. 이것은 a list가 아닌 a를 반환하고 str에서 작동 python3하며 단어 목록을 포함하며 알파가 아닌 문자 (밑줄, 대시 등)가 있어도 제대로 분할됩니다.

Generic Human에게 다시 한 번 감사드립니다!

https://github.com/keredson/wordninja


다음은 재귀 검색을 사용하는 솔루션입니다.

def find_words(instring, prefix = '', words = None):
    if not instring:
        return []
    if words is None:
        words = set()
        with open('/usr/share/dict/words') as f:
            for line in f:
                words.add(line.strip())
    if (not prefix) and (instring in words):
        return [instring]
    prefix, suffix = prefix + instring[0], instring[1:]
    solutions = []
    # Case 1: prefix in solution
    if prefix in words:
        try:
            solutions.append([prefix] + find_words(suffix, '', words))
        except ValueError:
            pass
    # Case 2: prefix not in solution
    try:
        solutions.append(find_words(suffix, prefix, words))
    except ValueError:
        pass
    if solutions:
        return sorted(solutions,
                      key = lambda solution: [len(word) for word in solution],
                      reverse = True)[0]
    else:
        raise ValueError('no solution')

print(find_words('tableapplechairtablecupboard'))
print(find_words('tableprechaun', words = set(['tab', 'table', 'leprechaun'])))

수확량

['table', 'apple', 'chair', 'table', 'cupboard']
['tab', 'leprechaun']

가능한 단어 목록을 보유 하는 trie 데이터 구조를 사용 하면 다음을 수행하는 것이 너무 복잡하지 않습니다.

  1. 고급 포인터 (연결된 문자열)
  2. 트라이에서 해당 노드를 조회하고 저장합니다.
  3. 트라이 노드에 자식이있는 경우 (예 : 더 긴 단어가 있음) 1로 이동합니다.
  4. 도달 한 노드에 자식이 없으면 가장 긴 단어 일치가 발생합니다. 결과 목록에 단어 (노드에 저장되거나 트라이 순회 중에 연결됨)를 추가하고 트라이에서 포인터를 재설정 (또는 참조 재설정) 한 다음 다시 시작합니다.

Unutbu의 솔루션은 매우 가까웠지만 코드를 읽기가 어려웠고 예상 한 결과를 얻지 못했습니다. Generic Human의 솔루션에는 단어 빈도가 필요하다는 단점이 있습니다. 모든 사용 사례에 적합하지는 않습니다.

다음은 Divide and Conquer 알고리즘을 사용하는 간단한 솔루션 입니다.

  1. 그것은 시도 단어의 수를 최소화 예는 find_words('cupboard')반환 ['cupboard']이 아니라 ['cup', 'board'](그 가정을 cupboard, cup그리고 board사전도에)
  2. 최적의 솔루션은 고유하지 않으며 아래 구현 솔루션을 반환 합니다 . find_words('charactersin')돌아올 수도 있고 돌아올 ['characters', 'in']수도 있습니다 ['character', 'sin'](아래 참조). 모든 최적의 솔루션을 반환하도록 알고리즘을 아주 쉽게 수정할 수 있습니다.
  3. 이 구현에서 솔루션은 적절한 시간에 실행되도록 메모 됩니다.

코드:

words = set()
with open('/usr/share/dict/words') as f:
    for line in f:
        words.add(line.strip())

solutions = {}
def find_words(instring):
    # First check if instring is in the dictionnary
    if instring in words:
        return [instring]
    # No... But maybe it's a result we already computed
    if instring in solutions:
        return solutions[instring]
    # Nope. Try to split the string at all position to recursively search for results
    best_solution = None
    for i in range(1, len(instring) - 1):
        part1 = find_words(instring[:i])
        part2 = find_words(instring[i:])
        # Both parts MUST have a solution
        if part1 is None or part2 is None:
            continue
        solution = part1 + part2
        # Is the solution found "better" than the previous one?
        if best_solution is None or len(solution) < len(best_solution):
            best_solution = solution
    # Remember (memoize) this solution to avoid having to recompute it
    solutions[instring] = best_solution
    return best_solution

3GHz 컴퓨터에서 약 5 초가 걸립니다.

result = find_words("thereismassesoftextinformationofpeoplescommentswhichisparsedfromhtmlbuttherearenodelimitedcharactersinthemforexamplethumbgreenappleactiveassignmentweeklymetaphorapparentlytherearethumbgreenappleetcinthestringialsohavealargedictionarytoquerywhetherthewordisreasonablesowhatsthefastestwayofextractionthxalot")
assert(result is not None)
print ' '.join(result)

html에서 구문 분석 된 사람들의 댓글에 대한 텍스트 정보의 reis 대량이지만 구분 된 문자가 없습니다. 예를 들어 thumb green apple 활성 할당 주간 은유 분명히 문자열에 thumb green apple 등이 있는지 여부를 쿼리 할 큰 사전이 있습니다. 단어가 합리적이므로 가장 빠른 추출 방법은 무엇입니까?


https://stackoverflow.com/users/1515832/generic-human 의 대답 은 훌륭합니다. 그러나 내가 본 최고의 구현은 Peter Norvig가 자신의 책 'Beautiful Data'에 직접 썼습니다.

그의 코드를 붙여 넣기 전에 Norvig의 방법이 더 정확한 이유를 확장 해 보겠습니다 (코드 측면에서 약간 느리고 길지만).

1) 데이터는 크기와 정밀도 측면에서 조금 더 좋습니다 (단순한 순위보다는 단어 수를 사용합니다) .2) 더 중요한 것은 접근 방식을 매우 정확하게 만드는 것은 n-gram의 논리입니다. .

그가 책에서 제공하는 예는 'sitdown'문자열을 분할하는 문제입니다. 이제 비 그램 문자열 분할 방법은 p ( 'sit') * p ( 'down')를 고려할 것이며, 이것이 p ( 'sitdown')보다 작 으면-매우 자주 발생합니다-분할되지 않습니다 하지만 우리는 (대부분의 경우) 원합니다.

그러나 bigram 모델을 사용하면 p ( 'sit down')를 bigram 대 p ( 'sitdown')으로 평가할 수 있으며 전자가 이깁니다. 기본적으로 bigrams를 사용하지 않으면 분할하는 단어의 확률을 독립적으로 처리합니다. 그렇지 않은 경우 일부 단어가 차례로 나타날 가능성이 더 높습니다. 불행히도 그것들은 종종 많은 경우에 함께 붙어서 스플리터를 혼동하는 단어입니다.

다음은 데이터 링크입니다 (3 개의 개별 문제에 대한 데이터이며 세분화는 단 하나입니다. 자세한 내용은 장을 참조하십시오) : http://norvig.com/ngrams/

다음은 코드 링크입니다. http://norvig.com/ngrams/ngrams.py

이 링크는 한동안 작동했지만 어쨌든 여기에 코드의 분할 부분을 복사하여 붙여 넣겠습니다.

import re, string, random, glob, operator, heapq
from collections import defaultdict
from math import log10

def memo(f):
    "Memoize function f."
    table = {}
    def fmemo(*args):
        if args not in table:
            table[args] = f(*args)
        return table[args]
    fmemo.memo = table
    return fmemo

def test(verbose=None):
    """Run some tests, taken from the chapter.
    Since the hillclimbing algorithm is randomized, some tests may fail."""
    import doctest
    print 'Running tests...'
    doctest.testfile('ngrams-test.txt', verbose=verbose)

################ Word Segmentation (p. 223)

@memo
def segment(text):
    "Return a list of words that is the best segmentation of text."
    if not text: return []
    candidates = ([first]+segment(rem) for first,rem in splits(text))
    return max(candidates, key=Pwords)

def splits(text, L=20):
    "Return a list of all possible (first, rem) pairs, len(first)<=L."
    return [(text[:i+1], text[i+1:]) 
            for i in range(min(len(text), L))]

def Pwords(words): 
    "The Naive Bayes probability of a sequence of words."
    return product(Pw(w) for w in words)

#### Support functions (p. 224)

def product(nums):
    "Return the product of a sequence of numbers."
    return reduce(operator.mul, nums, 1)

class Pdist(dict):
    "A probability distribution estimated from counts in datafile."
    def __init__(self, data=[], N=None, missingfn=None):
        for key,count in data:
            self[key] = self.get(key, 0) + int(count)
        self.N = float(N or sum(self.itervalues()))
        self.missingfn = missingfn or (lambda k, N: 1./N)
    def __call__(self, key): 
        if key in self: return self[key]/self.N  
        else: return self.missingfn(key, self.N)

def datafile(name, sep='\t'):
    "Read key,value pairs from file."
    for line in file(name):
        yield line.split(sep)

def avoid_long_words(key, N):
    "Estimate the probability of an unknown word."
    return 10./(N * 10**len(key))

N = 1024908267229 ## Number of tokens

Pw  = Pdist(datafile('count_1w.txt'), N, avoid_long_words)

#### segment2: second version, with bigram counts, (p. 226-227)

def cPw(word, prev):
    "Conditional probability of word, given previous word."
    try:
        return P2w[prev + ' ' + word]/float(Pw[prev])
    except KeyError:
        return Pw(word)

P2w = Pdist(datafile('count_2w.txt'), N)

@memo 
def segment2(text, prev='<S>'): 
    "Return (log P(words), words), where words is the best segmentation." 
    if not text: return 0.0, [] 
    candidates = [combine(log10(cPw(first, prev)), first, segment2(rem, first)) 
                  for first,rem in splits(text)] 
    return max(candidates) 

def combine(Pfirst, first, (Prem, rem)): 
    "Combine first and rem results into one (probability, words) pair." 
    return Pfirst+Prem, [first]+rem 

단어 목록을 DFA 로 사전 컴파일하면 (매우 느림) 입력 일치에 걸리는 시간은 문자열 길이에 비례합니다 (사실 문자열을 반복하는 것보다 약간 느립니다).

이것은 앞서 언급 한 트라이 알고리즘의보다 일반적인 버전입니다. 완전하지 않은 경우에만 언급합니다. 현재로서는 사용할 수있는 DFA 구현이 없습니다. RE2 는 작동하지만 컴파일 된 DFA 데이터를 버리고 NFA 검색을 수행하기 전에 Python 바인딩을 사용하여 DFA의 크기를 조정할 수 있는지 여부를 모르겠습니다.


다음은 JavaScript로 번역 된 허용 된 답변입니다 (node.js 및 https://github.com/keredson/wordninja의 "wordninja_words.txt"파일 필요 ).

var fs = require("fs");

var splitRegex = new RegExp("[^a-zA-Z0-9']+", "g");
var maxWordLen = 0;
var wordCost = {};

fs.readFile("./wordninja_words.txt", 'utf8', function(err, data) {
    if (err) {
        throw err;
    }
    var words = data.split('\n');
    words.forEach(function(word, index) {
        wordCost[word] = Math.log((index + 1) * Math.log(words.length));
    })
    words.forEach(function(word) {
        if (word.length > maxWordLen)
            maxWordLen = word.length;
    });
    console.log(maxWordLen)
    splitRegex = new RegExp("[^a-zA-Z0-9']+", "g");
    console.log(split(process.argv[2]));
});


function split(s) {
    var list = [];
    s.split(splitRegex).forEach(function(sub) {
        _split(sub).forEach(function(word) {
            list.push(word);
        })
    })
    return list;
}
module.exports = split;


function _split(s) {
    var cost = [0];

    function best_match(i) {
        var candidates = cost.slice(Math.max(0, i - maxWordLen), i).reverse();
        var minPair = [Number.MAX_SAFE_INTEGER, 0];
        candidates.forEach(function(c, k) {
            if (wordCost[s.substring(i - k - 1, i).toLowerCase()]) {
                var ccost = c + wordCost[s.substring(i - k - 1, i).toLowerCase()];
            } else {
                var ccost = Number.MAX_SAFE_INTEGER;
            }
            if (ccost < minPair[0]) {
                minPair = [ccost, k + 1];
            }
        })
        return minPair;
    }

    for (var i = 1; i < s.length + 1; i++) {
        cost.push(best_match(i)[0]);
    }

    var out = [];
    i = s.length;
    while (i > 0) {
        var c = best_match(i)[0];
        var k = best_match(i)[1];
        if (c == cost[i])
            console.log("Alert: " + c);

        var newToken = true;
        if (s.slice(i - k, i) != "'") {
            if (out.length > 0) {
                if (out[-1] == "'s" || (Number.isInteger(s[i - 1]) && Number.isInteger(out[-1][0]))) {
                    out[-1] = s.slice(i - k, i) + out[-1];
                    newToken = false;
                }
            }
        }

        if (newToken) {
            out.push(s.slice(i - k, i))
        }

        i -= k

    }
    return out.reverse();
}

상당히 평범한 역 추적이 될 것 같습니다. 문자열의 시작부터 시작하십시오. 단어가있을 때까지 바로 스캔하십시오. 그런 다음 나머지 문자열에서 함수를 호출합니다. 단어를 인식하지 않고 오른쪽 끝까지 스캔하면 함수는 "false"를 반환합니다. 그렇지 않으면 찾은 단어와 재귀 호출에서 반환 된 단어 목록을 반환합니다.

예 : "tableapple". "tab", "leap"순으로 검색되지만 "ple"에는 단어가 없습니다. "leapple"에는 다른 단어가 없습니다. "테이블"을 찾은 다음 "앱"을 찾습니다. "le"은 단어가 아니므로 사과를 시도하고 인식하고 반환합니다.

가능한 한 오래 가지려면 계속해서 올바른 솔루션을 내 보냅니다 (반환하지 않고). 그런 다음 선택한 기준 (최대, 최소, 평균 등)에 따라 최적의 항목을 선택하십시오.


unutbu의 솔루션을 기반으로 Java 버전을 구현했습니다.

private static List<String> splitWordWithoutSpaces(String instring, String suffix) {
    if(isAWord(instring)) {
        if(suffix.length() > 0) {
            List<String> rest = splitWordWithoutSpaces(suffix, "");
            if(rest.size() > 0) {
                List<String> solutions = new LinkedList<>();
                solutions.add(instring);
                solutions.addAll(rest);
                return solutions;
            }
        } else {
            List<String> solutions = new LinkedList<>();
            solutions.add(instring);
            return solutions;
        }

    }
    if(instring.length() > 1) {
        String newString = instring.substring(0, instring.length()-1);
        suffix = instring.charAt(instring.length()-1) + suffix;
        List<String> rest = splitWordWithoutSpaces(newString, suffix);
        return rest;
    }
    return Collections.EMPTY_LIST;
}

입력: "tableapplechairtablecupboard"

산출: [table, apple, chair, table, cupboard]

입력: "tableprechaun"

산출: [tab, leprechaun]


독일어의 경우 기계 학습을 사용하고 몇 단어의 문자열에 대해 꽤 잘 작동하는 CharSplit이 있습니다.

https://github.com/dtuggener/CharSplit


을 사용하라는 @miku의 제안을 확장 Trie하면 추가 전용 Trie은 비교적 간단하게 구현할 수 있습니다 python.

class Node:
    def __init__(self, is_word=False):
        self.children = {}
        self.is_word = is_word

class TrieDictionary:
    def __init__(self, words=tuple()):
        self.root = Node()
        for word in words:
            self.add(word)

    def add(self, word):
        node = self.root
        for c in word:
            node = node.children.setdefault(c, Node())
        node.is_word = True

    def lookup(self, word, from_node=None):
        node = self.root if from_node is None else from_node
        for c in word:
            try:
                node = node.children[c]
            except KeyError:
                return None

        return node

그런 다음 Trie단어 집합에서 기반 사전 을 구축 할 수 있습니다 .

dictionary = {"a", "pea", "nut", "peanut", "but", "butt", "butte", "butter"}
trie_dictionary = TrieDictionary(words=dictionary)

다음과 같은 트리가 생성됩니다 ( *단어의 시작 또는 끝을 나타냄).

* -> a*
 \\\ 
  \\\-> p -> e -> a*
   \\              \-> n -> u -> t*
    \\
     \\-> b -> u -> t*
      \\             \-> t*
       \\                 \-> e*
        \\                     \-> r*
         \
          \-> n -> u -> t*

단어를 선택하는 방법에 대한 휴리스틱과 결합하여이를 솔루션에 통합 할 수 있습니다. 예를 들어 짧은 단어보다 긴 단어를 선호 할 수 있습니다.

def using_trie_longest_word_heuristic(s):
    node = None
    possible_indexes = []

    # O(1) short-circuit if whole string is a word, doesn't go against longest-word wins
    if s in dictionary:
        return [ s ]

    for i in range(len(s)):
        # traverse the trie, char-wise to determine intermediate words
        node = trie_dictionary.lookup(s[i], from_node=node)

        # no more words start this way
        if node is None:
            # iterate words we have encountered from biggest to smallest
            for possible in possible_indexes[::-1]:
                # recurse to attempt to solve the remaining sub-string
                end_of_phrase = using_trie_longest_word_heuristic(s[possible+1:])

                # if we have a solution, return this word + our solution
                if end_of_phrase:
                    return [ s[:possible+1] ] + end_of_phrase

            # unsolvable
            break

        # if this is a leaf, append the index to the possible words list
        elif node.is_word:
            possible_indexes.append(i)

    # empty string OR unsolvable case 
    return []

이 함수를 다음과 같이 사용할 수 있습니다.

>>> using_trie_longest_word_heuristic("peanutbutter")
[ "peanut", "butter" ]

우리는 우리의 위치를 유지하기 때문에 Trie우리는 더 이상 긴 단어를 검색하면서, 우리는을 통과 trie(보다는 가능한 해결책에 한 번 가장에 2대한 시간 peanut: pea, peanut). 마지막 단락은 최악의 경우 문자열을 통해 숯불 모양으로 걷는 것을 방지합니다.

최종 결과는 몇 가지 검사입니다.

'peanutbutter' - not a word, go charwise
'p' - in trie, use this node
'e' - in trie, use this node
'a' - in trie and edge, store potential word and use this node
'n' - in trie, use this node
'u' - in trie, use this node
't' - in trie and edge, store potential word and use this node
'b' - not in trie from `peanut` vector
'butter' - remainder of longest is a word

이 솔루션의 이점은 주어진 접두사를 가진 더 긴 단어가 존재하는지 매우 빠르게 알 수 있다는 점입니다. 따라서 사전에 대해 철저하게 시퀀스 조합을 테스트 할 필요가 없습니다. 또한 unsolvable다른 구현에 비해 상대적으로 저렴한 답변 을 얻을 수 있습니다.

이 솔루션의 단점은 초기 trie구축 비용과 메모리 공간이 크다는 것 trie입니다.


문자열에 포함 된 단어의 전체 목록이있는 경우 :

word_list = ["table", "apple", "chair", "cupboard"]

목록 이해력을 사용하여 목록을 반복하여 단어와 단어가 나타나는 횟수를 찾습니다.

string = "tableapplechairtablecupboard"

def split_string(string, word_list):

    return ("".join([(item + " ")*string.count(item.lower()) for item in word_list if item.lower() in string])).strip()


이 함수는 string목록 순서대로 단어 출력을 반환 합니다.table table apple chair cupboard


당신은 당신의 어휘를 식별 할 필요가 있습니다-아마도 어떤 무료 단어 목록이든 가능합니다.

완료되면 해당 어휘를 사용하여 접미사 트리를 만들고 입력 스트림을 http://en.wikipedia.org/wiki/Suffix_tree 와 일치시킵니다 .

참고 URL : https://stackoverflow.com/questions/8870261/how-to-split-text-without-spaces-into-list-of-words

반응형