cndict 0.7.1 → 0.7.3
raw patch · 7 files changed
+227/−322 lines, 7 filesdep +arraydep −binarydep −cassavadep −containers
Dependencies added: array
Dependencies removed: binary, cassava, containers, vector
Files
- cndict.cabal +6/−9
- data/cedict_1_0_ts_utf-8_mdbg.txt too large to diff
- data/dict.sorted too large to diff
- data/dict.txt.big too large to diff
- src/Data/Chinese/CCDict.hs +181/−253
- src/Data/Chinese/Frequency.hs +0/−36
- src/Data/Chinese/Segmentation.hs +40/−24
cndict.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: cndict-version: 0.7.1+version: 0.7.3 synopsis: Chinese/Mandarin <-> English dictionary, Chinese lexer. -- description: license: PublicDomain@@ -16,24 +16,21 @@ cabal-version: >=1.8 data-files:- data/cedict_1_0_ts_utf-8_mdbg.txt- data/dict.txt.big+ data/dict.sorted source-repository head type: git location: git://github.com/Lemmih/cndict.git library- exposed-modules: Data.Chinese.CCDict, Data.Chinese.Pinyin,- Data.Chinese.Frequency, Data.Chinese.Segmentation+ exposed-modules: Data.Chinese.CCDict,+ Data.Chinese.Pinyin,+ Data.Chinese.Segmentation other-modules: Paths_cndict build-depends: base == 4.*, text >= 0.11.0.0,- containers >= 0.5.0.0,- vector >= 0.10.0.0, bytestring >= 0.9.0.0,- cassava >= 0.3.0.0,- binary+ array hs-source-dirs: src ghc-options: -Wall ghc-prof-options: -auto-all
− data/cedict_1_0_ts_utf-8_mdbg.txt
file too large to diff
+ data/dict.sorted view
file too large to diff
− data/dict.txt.big
file too large to diff
src/Data/Chinese/CCDict.hs view
@@ -3,307 +3,235 @@ {-# LANGUAGE OverloadedStrings #-} -- | Simplified Chinese <-> English dictionary with pinyin phonetics. module Data.Chinese.CCDict- ( CCDict+ ( initiate , Entry(..)- , load- , parse- , lookup+ , ppEntry+ , entryVariants+ , entrySimplified+ , entryTraditional+ , entryWordFrequency+ , entryPinyin+ , Variant(..)+ , lookupMatch , lookupMatches- , ccDict ) where -import qualified Data.ByteString as B import Data.Char-import Data.IntMap (IntMap)-import qualified Data.IntMap.Strict as IntMap-import Data.List (foldl', maximumBy, nub) import Data.Maybe import Data.Ord import Data.Text (Text) import qualified Data.Text as T-import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import Paths_cndict import Prelude hiding (lookup) import System.IO.Unsafe (unsafePerformIO) -import Data.Tree -import qualified Data.Chinese.Frequency as Frequency-import Data.Chinese.Pinyin--import Data.Chinese.Frequency hiding (lookup)------------------------------------------------------- Dictionary+import qualified Data.Text.Internal as T+import qualified Data.Text.Array as T+import qualified Data.Array.Unboxed as U+import qualified Data.Text.Read as T+import Control.Exception (evaluate) +-- | Load DB into memory. Otherwise it happens when the DB+-- is first used.+initiate :: IO ()+initiate = do+ evaluate ccDict+ return () --- | Dictionary entry-data Entry = Entry- { entrySimplified :: !Text- , entryTraditional :: !Text- , entryPinyin :: [Text]- , entryDefinition :: [[Text]]- } deriving ( Read, Show, Eq, Ord )+data CCDict = CCDict !T.Array !Int (U.UArray Int Int) -type RawEntry = Text+mkCCDict :: Text -> CCDict+mkCCDict text@(T.Text arr _ len) =+ CCDict arr len+ (U.listArray (0,n-1) offsets)+ where+ ls = T.lines text+ offsets =+ [ offset+ | T.Text _ offset _length <- ls ]+ n = length ls --- entryPinyin :: Entry -> [Text]--- entryPinyin = map (T.unwords . map toToneMarks . T.words) . entryPinyinRaw+ccDict :: CCDict+ccDict = mkCCDict utfData+ where+ utfData = unsafePerformIO $ do+ path <- getDataFileName "data/dict.sorted"+ T.readFile path -type CCDict = IntMap CCTrieEntry-data CCTrieEntry- = CCTrieEntry {-# UNPACK #-} !RawEntry !CCDict- | CCTrieEntryEnd {-# UNPACK #-} !RawEntry- | CCTrieNoEntry !CCDict- deriving ( Show )+ccDictNth :: Int -> CCDict -> Text+ccDictNth n (CCDict arr totalLen offsets) =+ T.text arr offset len+ where+ lastIdx = snd (U.bounds offsets)+ offset = offsets U.! n+ len+ | lastIdx == n = totalLen - offset - 1+ | otherwise = offsets U.! (n+1) - offset - 1 +bounds :: CCDict -> (Int, Int)+bounds (CCDict _ _ offsets) = U.bounds offsets --- instance Binary CCTrieEntry where--- put (CCTrieEntry entry rest) = put entry >> put rest--- get = CCTrieEntry <$> get <*> get+findPrefix :: CCDict -> Int -> Int -> Int -> Text -> Maybe (Int,Int)+findPrefix dict maxUpper lower upper key+ | lower > upper = Nothing+ | otherwise =+ case compare (T.take len key) (T.take len val) of+ LT -> findPrefix dict (middle-1) lower (middle-1) key+ GT -> findPrefix dict maxUpper (middle+1) upper key+ EQ ->+ case compare (T.length key) (T.length val) of+ GT -> findPrefix dict maxUpper (middle+1) upper key+ _ -> Just $ fromMaybe (middle, maxUpper) $+ findPrefix dict maxUpper lower (middle-1) key+ where+ middle = (upper - lower) `div` 2 + lower+ val = T.takeWhile (/='\t') $ ccDictNth middle dict+ len = min (T.length val) (T.length key) --- | Load dictionary from file.-load :: FilePath -> IO CCDict-load path = parse `fmap` T.readFile path+lookupMatches :: Text -> Maybe [Entry]+lookupMatches key+ | T.null key = Nothing+lookupMatches key =+ if null entries+ then Nothing+ else Just entries+ where+ keys = tail $ T.inits key+ entries = worker (bounds ccDict) keys+ worker _ [] = []+ worker (lower, upper) (k:ks) =+ case findPrefix ccDict upper lower upper k of+ Nothing -> []+ Just (first, newUpper) ->+ maybe id (:) (scrapeEntry ccDict first k) $+ worker (first, newUpper) ks --- | Load dictionary from unicode text.-parse :: Text -> CCDict-parse txt = fromList- [ (key, line)- | line <- T.lines txt- , Just entry <- [parseLine line]- , key <- nub [entrySimplified entry, entryTraditional entry] ]+lookupMatch :: Text -> Maybe Entry+lookupMatch key+ | T.null key = Nothing+ | otherwise =+ case findPrefix ccDict upper lower upper key of+ Nothing -> Nothing+ Just (first, _newUpper) ->+ scrapeEntry ccDict first key+ where+ (upper, lower) = bounds ccDict --- | O(n). Lookup dictionary entry for a string of simplified chinese.-lookup :: Text -> CCDict -> Maybe Entry-lookup key trie =- case map ord $ T.unpack key of+scrapeEntry :: CCDict -> Int -> Text -> Maybe Entry+scrapeEntry dict nth key =+ case variants of [] -> Nothing- (x:xs) -> fmap parseRawEntry (go xs =<< IntMap.lookup x trie)- where- go _ (CCTrieEntryEnd es) = Just es- go [] (CCTrieEntry es _) = Just es- go [] (CCTrieNoEntry _) = Nothing- go (x:xs) (CCTrieEntry es m) = Just (fromMaybe es (go xs =<< IntMap.lookup x m))- go (x:xs) (CCTrieNoEntry m) = (go xs =<< IntMap.lookup x m)--lookupMatches :: Text -> CCDict -> Maybe [Entry]-lookupMatches key trie =- case map ord $ T.unpack key of- [] -> Nothing- (x:xs) ->- case fmap (map parseRawEntry . go xs) (IntMap.lookup x trie) of- Just [] -> Nothing- other -> other+ (v:vs) -> Just (Entry v vs) where- go _ (CCTrieEntryEnd e) = [e]- go [] (CCTrieNoEntry _) = []- go [] (CCTrieEntry e _) = [e]- go (x:xs) (CCTrieNoEntry m) = maybe [] (go xs) (IntMap.lookup x m)- go (x:xs) (CCTrieEntry e m) = e : maybe [] (go xs) (IntMap.lookup x m)-+ variants = scrapeVariants dict nth key --- 点出发--- [[点,出发],[点出,发]]--- 出发点--- [[出发]]--- 穿上外套--- This can be broken up in two ways: 穿 上外 套 and 穿上 外套--- We want the second, more greedy tokenization.-lookupNonDet :: Text -> CCDict -> Maybe [[Entry]]-lookupNonDet key trie = do- entries <- lookupMatches key trie- let longest = maximumBy (comparing (T.length . entrySimplified)) entries+scrapeVariants :: CCDict -> Int -> Text -> [Variant]+scrapeVariants dict nth key+ | nth > snd (bounds dict) = []+ | T.takeWhile (/='\t') raw == key =+ parseVariant raw : scrapeVariants dict (nth+1) key+ | otherwise = []+ where+ raw = ccDictNth nth dict - if length entries == 1- then return [entries]- else do- return $ whenEmpty [[longest]] $ maybe [] beGreedy $ sequence $ do- entry1 <- entries- case lookupMatches (T.drop (T.length (entrySimplified entry1)) key) trie of- Nothing -> return Nothing- Just entries2 -> do- entry2 <- entries2- return $ Just (entry1, entry2)+parseVariant :: Text -> Variant+parseVariant line =+ case T.splitOn "\t" line of+ [chinese, count, pinyin, english] ->+ mkVariant chinese chinese count pinyin english+ [traditional, simplified, "T", count, pinyin, english] ->+ mkVariant traditional simplified count pinyin english+ [simplified, traditional, "S", count, pinyin, english] ->+ mkVariant traditional simplified count pinyin english+ _ -> error $ "invalid variant: " ++ T.unpack line where- filterCompact :: [[Entry]] -> [[Entry]]- filterCompact lst =- let mostCompact = minimum (map length lst)- in [ entries | entries <- lst, length entries == mostCompact ]- filterLongest :: [[Entry]] -> [[Entry]]- filterLongest lst =- let len = sum . map (T.length . entrySimplified)- longest = maximum (map len lst)- in [ entries | entries <- lst, len entries == longest ]- beGreedy :: [(Entry,Entry)] -> [[Entry]]- beGreedy lst =- let longestFirst = maximum (map (T.length . entrySimplified . fst) lst)- longest = maximum [ T.length (entrySimplified e1) + T.length (entrySimplified e2)- | (e1,e2) <- lst- , T.length (entrySimplified e1) < longestFirst ]- in filterCompact $ filterLongest $ nub $- [ [e1,e2]- | (e1,e2) <- lst- , T.length (entrySimplified e1) < longest- , T.length (entrySimplified e1) + T.length (entrySimplified e2) /= 2 ] ++- [ [e1]- | (e1,_) <- lst- , T.length (entrySimplified e1) == longest ]- whenEmpty lst [] = lst- whenEmpty _ lst = lst- -- step Nothing _ = []- -- step (Just [x]) _ = return [x]- -- step (Just lst) fn = lst >>= fn- -- beGreedy lst =- -- let len = sum . map (T.length . entrySimplified)- -- longest = maximum (map len lst')- -- mostCompact = minimum (map length lst)- -- lst' = filter (\x -> length x == mostCompact) lst- -- in filter (\x -> len x == longest) lst'- -- toMaybe [] = Nothing- -- toMaybe lst = Just lst+ mkVariant traditional simplified countStr pinyin english = Variant+ { variantTraditional = traditional+ , variantSimplified = simplified+ , variantWordFrequency = count+ , variantPinyin = pinyin+ , variantDefinitions = splitDefinition english }+ where+ Right (count,_) = T.decimal countStr +--freqLookup_ :: FreqMap -> Text -> Maybe Int+--freqLookup_ freq key = worker (bounds freq)+-- where+-- worker (lower, upper)+-- | lower > upper = Nothing+-- worker (lower, upper) =+-- let middle = (upper - lower) `div` 2 + lower+-- val = freqNth middle freq+-- [word, countStr] = T.words val+-- Right (count,_) = T.decimal countStr+-- in case compare key word of+-- LT -> worker (lower, middle-1)+-- GT -> worker (middle+1, upper)+-- EQ -> Just count+ ----------------------------------------------------- Tokenizer+-- Dictionary --- Interesting case: 他的话 tokenizes to [他,的话] by both google translate and--- MDGB. The correct tokenization is [他,的,话]. Not sure if it can be fixed without--- adding an entry for 他的 in the dictionary.--- TODO: Mark text inclosed in curly brackets as unknown words.--- FIXME: 不想 should tokenize to [不,想]--- FIXME: 那是 should tokenize to [那,是]+-- | Dictionary entry+--data Entry = Entry+-- { entrySimplified :: !Text+-- , entryTraditional :: !Text+-- , entryPinyin :: [Text]+-- , entryDefinition :: [[Text]]+-- } deriving ( Read, Show, Eq, Ord ) +data Entry = Entry Variant [Variant]+ deriving (Show, Read, Eq, Ord)+data Variant = Variant+ { variantSimplified :: !Text+ , variantTraditional :: !Text+ , variantWordFrequency :: !Int+ , variantPinyin :: !Text+ , variantDefinitions :: [Text]+ } deriving ( Read, Show, Eq, Ord ) ------------------------------------------------------ Dictionary trie+entryVariants :: Entry -> [Variant]+entryVariants (Entry v vs) = v:vs --- union :: CCDict -> CCDict -> CCDict--- union = IntMap.unionWith joinTrie+dominantVariant :: Entry -> Variant+dominantVariant (Entry v vs) =+ foldr dom v vs+ where+ dom v1 v2+ | variantWordFrequency v1 < variantWordFrequency v2 =+ v2+ | otherwise =+ v1 --- joinTrie newValue oldValue-joinTrie :: CCTrieEntry -> CCTrieEntry -> CCTrieEntry-joinTrie (CCTrieNoEntry t1) (CCTrieNoEntry t2) = CCTrieNoEntry (IntMap.unionWith joinTrie t1 t2)-joinTrie (CCTrieNoEntry t1) (CCTrieEntry e t2) = CCTrieEntry e (IntMap.unionWith joinTrie t1 t2)-joinTrie (CCTrieNoEntry t1) (CCTrieEntryEnd e) = CCTrieEntry e t1-joinTrie (CCTrieEntry e t1) (CCTrieNoEntry t2) = CCTrieEntry e (IntMap.unionWith joinTrie t1 t2)-joinTrie (CCTrieEntry e1 t1) (CCTrieEntry e2 t2) =- CCTrieEntry (joinRawEntry e1 e2) (IntMap.unionWith joinTrie t1 t2)-joinTrie (CCTrieEntry e1 t2) (CCTrieEntryEnd e2) = CCTrieEntry (joinRawEntry e1 e2) t2-joinTrie (CCTrieEntryEnd e) (CCTrieNoEntry t) = CCTrieEntry e t-joinTrie (CCTrieEntryEnd e1) (CCTrieEntry e2 t) = CCTrieEntry (joinRawEntry e1 e2) t-joinTrie (CCTrieEntryEnd e1) (CCTrieEntryEnd e2) = CCTrieEntryEnd (joinRawEntry e1 e2)+entrySimplified :: Entry -> Text+entrySimplified = variantSimplified . dominantVariant -joinRawEntry :: RawEntry -> RawEntry -> RawEntry-joinRawEntry e1 e2 = T.concat [e1, "\n", e2]+entryTraditional :: Entry -> Text+entryTraditional = variantTraditional . dominantVariant --- joinEntry newValue oldValue-joinEntry :: Entry -> Entry -> Entry-joinEntry e1 e2 = Entry- { -- The simplified characters must be identical- entrySimplified = entrySimplified e1- -- 了 maps to two traditional characters: 了 and 瞭.- -- In these cases, choose the same as the simplified.- , entryTraditional =- if entryTraditional e1 == entrySimplified e1 ||- entryTraditional e2 == entrySimplified e1- then entrySimplified e1- else entryTraditional e1- , entryPinyin = entryPinyin e2 ++ entryPinyin e1- , entryDefinition = entryDefinition e2 ++ entryDefinition e1 }+entryWordFrequency :: Entry -> Int+entryWordFrequency = variantWordFrequency . dominantVariant --- unions :: [CCDict] -> CCDict--- unions = foldl' union IntMap.empty+entryPinyin :: Entry -> [Text]+entryPinyin = map variantPinyin . entryVariants -fromList :: [(Text, RawEntry)] -> CCDict--- fromList = unions . map singleton-fromList = foldl' (flip insert) IntMap.empty+ppEntry :: Entry -> Text+ppEntry = T.intercalate "\n" . map ppVariant . entryVariants -insert :: (Text, RawEntry) -> CCDict -> CCDict-insert (key, entry) = go (T.unpack key)+ppVariant :: Variant -> Text+ppVariant (Variant simplified traditional frequency pinyin english) =+ T.intercalate "\t"+ [simplified, traditional, count, pinyin, english'] where- go :: [Char] -> CCDict -> CCDict- go [] _ = error "insert: Invalid entry."- go [x] t =- IntMap.insertWith joinTrie (ord x) (CCTrieEntryEnd entry) t- go (x:xs) t =- IntMap.alter (go' xs) (ord x) t- go' xs Nothing = Just $ CCTrieNoEntry (go xs IntMap.empty)- go' xs (Just trie) = Just $- case trie of- CCTrieNoEntry t -> CCTrieNoEntry $ go xs t- CCTrieEntry e t -> CCTrieEntry e $ go xs t- CCTrieEntryEnd e -> CCTrieEntry e $ go xs IntMap.empty+ count = T.pack $ show frequency+ english' = T.intercalate "/" english --- singleton :: Entry -> CCDict--- singleton entry = go (T.unpack (entryChinese entry))--- where--- go [] = error "singleton: Invalid entry."--- go [x] = IntMap.singleton (ord x) (CCTrieEntryEnd entry)--- go (x:xs) = IntMap.singleton (ord x) (CCTrieNoEntry (go xs)) -parseRawEntry :: Text -> Entry-parseRawEntry = foldr1 joinEntry . mapMaybe parseLine . T.lines--parseLine :: Text -> Maybe Entry-parseLine line | "#" `T.isPrefixOf` line = Nothing-parseLine line =- Just Entry- { entrySimplified = simplified- , entryTraditional = traditional- , entryPinyin = [T.unwords $ map toToneMarks $ T.words pinyin]- , entryDefinition = [splitDefinition english] }- -- , entryPinyin = V.singleton $ T.unwords $ map toToneMarks $ T.words $ T.tail $- -- T.init $ T.unwords (pinyin ++ [pin])- -- , entryDefinition = V.singleton $ splitDefinition (T.unwords english) }- where- (traditional, line') = T.breakOn " " line- (simplified, line'') = T.breakOn " " (T.drop 1 line')- (pinyin_, english_) = T.breakOn "/" (T.drop 1 line'')- !english = english_- !pinyin = T.dropAround (\c -> isSpace c || c == '[' || c == ']') pinyin_- -- firstSep = breakOn " ", breakOn " ", breakOn "/"- -- (_traditional : chinese : rest) = T.words (T.copy line)- -- (pinyin, (pin : english)) = break (\word -> T.count "]" word > 0) rest- -- /first/second/third/ -> [first, second, third] splitDefinition :: Text -> [Text] splitDefinition = filter (not . T.null) . T.splitOn "/" . T.dropAround isSpace -------------------------------------------------------- Embedded dictionary--remove :: Text -> CCDict -> CCDict-remove = worker . map ord . T.unpack- where- worker [] dict = dict- worker (x:xs) dict =- IntMap.update (fn xs) x dict- fn xs (CCTrieNoEntry rest) = Just $ CCTrieNoEntry (worker xs rest)- fn [] CCTrieEntryEnd{} = Nothing- fn _ (CCTrieEntryEnd entry) = Just $ CCTrieEntryEnd entry- fn [] (CCTrieEntry _ rest) = Just $ CCTrieNoEntry rest- fn xs (CCTrieEntry e rest) = Just $ CCTrieEntry e (worker xs rest)---- | Embedded dictionary.-ccDict :: CCDict-ccDict =- remove "得很" $- remove "那是" $ remove "到了" $- remove "里人" $ remove "多事" $- remove "你我" $ remove "家的" $- parse $ T.decodeUtf8 raw- where- -- raw = $(embedFile "data/cedict_1_0_ts_utf-8_mdbg.txt")- raw = unsafePerformIO $ do- path <- getDataFileName "data/cedict_1_0_ts_utf-8_mdbg.txt"- B.readFile path---- ccDict' :: CCDict--- ccDict' = decode (BL.fromStrict raw)--- where--- raw = $(embedFile "data/cedict_1_0_ts_utf-8_mdbg.txt.binary")
− src/Data/Chinese/Frequency.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE BangPatterns #-}-module Data.Chinese.Frequency- ( FreqMap- , freqMap- ) where--import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import Data.Map (Map)-import qualified Data.Map.Strict as M-import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.IO as T-import qualified Data.Text.Read as T-import Data.Text.Encoding-import Paths_cndict-import System.IO.Unsafe (unsafePerformIO)--type FreqMap = Map Text Int--freqMap :: FreqMap-freqMap = mkFreqMap rows- where- utfData = unsafePerformIO $ do- path <- getDataFileName "data/dict.txt.big"- T.readFile path- rows = T.lines utfData--mkFreqMap :: [Text] -> FreqMap-mkFreqMap rows = M.fromListWith max- [ (word, count)- | (n,row) <- zip [0..] rows- , let [word,countStr,_type] = T.words row- Right (count,_) = T.decimal countStr- ]
src/Data/Chinese/Segmentation.hs view
@@ -2,20 +2,20 @@ module Data.Chinese.Segmentation ( Token(..) , Entry(..)+ , entrySimplified+ , entryTraditional+ , entryPinyin+ , tokenizer- , tokenizer_ , ppTokens , toTraditional , toSimplified ) where -import Data.Chinese.CCDict (Entry(..))+import Data.Chinese.CCDict (Entry(..), entrySimplified, entryTraditional, entryWordFrequency, entryPinyin) import qualified Data.Chinese.CCDict as CC-import qualified Data.Chinese.Frequency as F import qualified Data.Text as T-import qualified Data.Map.Strict as M import Data.Text (Text)-import qualified Data.IntMap as IntMap import Data.List import Data.Maybe import Control.Monad@@ -29,14 +29,14 @@ -- [[A,AB],[B],[C]] -- [ [[A,B],[AB]] -- , [[C]] ]-splitText :: CC.CCDict -> Text -> [[Token]]-splitText dict txt =- [ case CC.lookupMatches offset dict of+splitText :: Text -> [[Token]]+splitText txt =+ [ case CC.lookupMatches offset of Nothing -> [UnknownWord char] Just entries -> map KnownWord entries- | n <- [0..T.length txt-1]- , let offset = T.drop n txt- char = T.take 1 offset ]+ | offset <- T.tails txt+ , not (T.null offset)+ , let char = T.take 1 offset ] -- [[A,AB],[B]] -> [ [[A,B],[AB]] ] -- [[A,AB],[BC],[C]] -> [[[A,BC],[AB,C]]]@@ -62,6 +62,22 @@ let maxLength = maximum (map tokenLength ts) in 1 + worker (max l maxLength - 1) tss +filterExceptions :: [[Token]] -> [[Token]]+filterExceptions lst = worker lst+ where+ worker (x:xs) =+ let ws = [ entrySimplified e | KnownWord e <- x ] in+ case ws `elem` exceptions of+ False -> worker xs+ True -> [x]+ worker [] = lst+ exceptions =+ [["家", "中餐馆"]+ ,["这", "位子"]+ ,["十", "分钟"]+ ,["一", "点钟"]+ ,["合上", "书"]]+ greedyGroups :: [[[Token]]] -> [[[Token]]] greedyGroups = map worker where@@ -69,7 +85,7 @@ filter (onlyWithLength (minimum $ map length tss) (maximum $ map (maximum.map tokenLength) tss)) tss onlyWithLength len tlen ts =- length ts == len && maximum (map tokenLength ts) == tlen+ length ts == len -- && maximum (map tokenLength ts) == tlen tokenLength UnknownWord{} = 0 tokenLength (KnownWord e) = T.length (entrySimplified e)@@ -115,22 +131,21 @@ tokenScore UnknownWord{} = Nothing tokenScore (KnownWord e) -- | T.length (entrySimplified e) == 1 = Nothing- | otherwise = Just $ wordCount (entrySimplified e)+ | otherwise = Just $ entryWordFrequency e -wordCount :: Text -> Int-wordCount txt =- case M.lookup txt F.freqMap of- Just n -> n- Nothing -> 0 {-minimum- [ M.findWithDefault 1 char F.freqMap- | char <- T.chunksOf 1 txt ]-}+--wordCount :: Text -> Int+--wordCount txt =+-- case F.wordFrequency txt of+-- Just n -> n+-- Nothing -> 0 {-minimum+-- [ M.findWithDefault 1 char F.freqMap+-- | char <- T.chunksOf 1 txt ]-} -- | Break a string of simplified chinese down to a list of tokens. tokenizer :: Text -> [Token]-tokenizer = tokenizer_ CC.ccDict--tokenizer_ :: CC.CCDict -> Text -> [Token]-tokenizer_ dict = flattenGroups . greedyGroups . findGroups . splitText dict+tokenizer =+ flattenGroups . greedyGroups . map filterExceptions .+ findGroups . splitText _ppSegmentationTests = forM_ wrong $ \(txt, expected, got) -> do@@ -200,6 +215,7 @@ , ("我合上书准备离开", "我 合上 书 准备 离开") , ("他的话","他 的 话")+ , ("你用什么方法学习","你 用 什么 方法 学习") ]