nkjp 0.1.1 → 0.2.0
raw patch · 7 files changed
+260/−205 lines, 7 filesdep ~data-namednew-component:exe:named2enamex
Dependency ranges changed: data-named
Files
- Data/NKJP/Morphosyntax.hs +0/−39
- Data/NKJP/Named.hs +0/−108
- Text/NKJP/Morphosyntax.hs +45/−28
- Text/NKJP/Named.hs +135/−25
- Text/NKJP/Tar.hs +40/−0
- nkjp.cabal +11/−5
- tools/named2enamex.hs +29/−0
− Data/NKJP/Morphosyntax.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE DeriveFunctor #-}---- | Data types for the morphosytnax layer of the NKJP corpus.--module Data.NKJP.Morphosyntax-( Para (..)-, Sent (..)-, Seg (..)-, Lex (..)-) where---- | A paragraph.-data Para t = Para- { paraID :: t- , sentences :: [Sent t] }- deriving (Show, Functor)---- | A sentence.-data Sent t = Sent- { sentID :: t- , segments :: [Seg t] }- deriving (Show, Functor)---- | A segment.-data Seg t = Seg- { segID :: t - , orth :: t- , nps :: Bool- , lexs :: [Lex t]- , choice :: (t, t) }- deriving (Show, Functor)---- | A lexciacal entry, potential interpretation of the segment.-data Lex t = Lex- { lexID :: t- , base :: t- , ctag :: t- , msds :: [(t, t)] }- deriving (Show, Functor)
− Data/NKJP/Named.hs
@@ -1,108 +0,0 @@-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE RecordWildCards #-}---- | Data types for the named entities layer of the NKJP corpus.--module Data.NKJP.Named-( Cert (..)-, Ptr (..)-, Deriv (..)-, Para (..)-, Sent (..)-, NE (..)-, mkForest-) where--import Data.Named.Graph (toForest, mkGraph)-import Data.Named.Tree (mapTrees)-import Data.NKJP.Morphosyntax (Seg, segID)-import qualified Data.Map as M-import qualified Data.Tree as T---- | A certainty of an annotator.-data Cert- = High- | Medium- | Low- deriving (Show)---- | A pointer.-data Ptr t- -- | Of #id form.- = Local- { target :: t }- -- | Of loc#id form.- | Global- { target :: t- , location :: t }- deriving (Show, Functor)---- | A derivation structure.-data Deriv t = Deriv- { derivType :: t - , derivFrom :: t }- deriving (Show, Functor)---- | A paragraph.-data Para t = Para- { paraID :: t- , sentences :: [Sent t] }- deriving (Show, Functor)---- | A sentence.-data Sent t = Sent- { sentID :: t- , names :: [NE t] }- deriving (Show, Functor)---- | A segment element in a file. -data NE t = NE- { neID :: t- , derived :: Maybe (Deriv t)- , neType :: t- , subType :: Maybe t- , orth :: t- -- | Left base or Right when.- , base :: Either t t- , cert :: Cert- , certComment :: Maybe t- , ptrs :: [Ptr t] }- deriving (Show)--instance Functor NE where- fmap f NE{..} = NE- { neID = f neID- , derived = fmap (fmap f) derived- , neType = f neType- , subType = fmap f subType- , orth = f orth- , base = case base of- Left x -> Left (f x)- Right x -> Right (f x)- , cert = cert- , certComment = fmap f certComment- , ptrs = map (fmap f) ptrs }---- | Make NE forest from a segment list and a list of NEs, both lists--- corresponding to the same sentence.-mkForest :: Ord t => [Seg t] -> [NE t] -> T.Forest (Either (NE t) (Seg t))-mkForest xs ns =- mapTrees decode (toForest graph)- where- -- Position of segment ID- pos = (M.!) $ M.fromList (zip (map segID xs) [0..])- -- Segment on the given position- word = (M.!) $ M.fromList (zip [0..] xs)- -- NE with given ID- name = (M.!) $ M.fromList [(neID ne, ne) | ne <- ns]-- graph = mkGraph (0, length xs - 1)- [ ( neID ne- , map resolve (ptrs ne) )- | ne <- ns ]-- resolve (Local ptr) = Left ptr- resolve (Global ptr _) = Right (pos ptr)-- decode (Left neID) = Left (name neID)- decode (Right k) = Right (word k)
Text/NKJP/Morphosyntax.hs view
@@ -1,26 +1,58 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveFunctor #-} -- | Parsing the NKJP morphosyntax layer. module Text.NKJP.Morphosyntax-( parseMorph+(+-- * Data types+ Para (..)+, Sent (..)+, Seg (..)+, Lex (..)++-- * Parsing+, parseMorph , readMorph , readCorpus-, module Data.NKJP.Morphosyntax ) where -import System.FilePath (takeBaseName) import Data.Maybe (isJust) import qualified Data.Text.Lazy as L import qualified Data.Text.Lazy.IO as L-import qualified Data.Text.Lazy.Encoding as L-import qualified Data.ByteString.Lazy as BS-import qualified Codec.Compression.GZip as GZip-import qualified Codec.Archive.Tar as Tar import Text.XML.PolySoup-import Data.NKJP.Morphosyntax+import qualified Text.NKJP.Tar as Tar +-- | A paragraph.+data Para t = Para+ { paraID :: t+ , sentences :: [Sent t] }+ deriving (Show, Functor)++-- | A sentence.+data Sent t = Sent+ { sentID :: t+ , segments :: [Seg t] }+ deriving (Show, Functor)++-- | A segment.+data Seg t = Seg+ { segID :: t + , orth :: t+ , nps :: Bool+ , lexs :: [Lex t]+ , choice :: (t, t) }+ deriving (Show, Functor)++-- | A lexciacal entry, potential interpretation of the segment.+data Lex t = Lex+ { lexID :: t+ , base :: t+ , ctag :: t+ , msds :: [(t, t)] }+ deriving (Show, Functor)+ -- | TEI NKJP ann_morphosyntax parser. type P a = XmlParser L.Text a @@ -80,23 +112,8 @@ readMorph :: FilePath -> IO [Para L.Text] readMorph morphPath = parseMorph <$> L.readFile morphPath --- | Parse NCP the .tar.gz corpus.-readCorpus :: FilePath -> IO [(FilePath, [Para L.Text])]-readCorpus tarPath = do- map parseEntry . withBase "ann_morphosyntax" <$> readTar tarPath--readTar :: FilePath -> IO [Tar.Entry]-readTar tar- = Tar.foldEntries (:) [] (error . show)- . Tar.read . GZip.decompress- <$> BS.readFile tar--parseEntry :: Tar.Entry -> (FilePath, [Para L.Text])-parseEntry entry =- (Tar.entryPath entry, parseMorph content)- where- (Tar.NormalFile binary _) = Tar.entryContent entry- content = L.decodeUtf8 binary--withBase :: String -> [Tar.Entry] -> [Tar.Entry]-withBase baseName = filter ((==baseName) . takeBaseName . Tar.entryPath)+-- | Parse all ann_morphosyntax.xml files from the NCP .tar.gz file.+-- Directories will be processed in an ascending order (with+-- respect to directory names).+readCorpus :: FilePath -> IO [(FilePath, Maybe [Para L.Text])]+readCorpus = Tar.readCorpus "ann_morphosyntax" parseMorph
Text/NKJP/Named.hs view
@@ -1,25 +1,130 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE RecordWildCards #-} -- | Parsing the NKJP named entity layer. module Text.NKJP.Named-( parseNamed+(+-- * Data types+ Cert (..)+, Ptr (..)+, Deriv (..)+, Para (..)+, Sent (..)+, NE (..)++-- * Parsing+, parseNamed , readNamed , readCorpus-, module Data.NKJP.Named+, readTrees++-- * Utilities+, mkForest ) where -import System.FilePath (takeBaseName)+import Data.Maybe (mapMaybe)+import qualified Data.Map as M+import qualified Data.Tree as T import qualified Data.Text.Lazy as L import qualified Data.Text.Lazy.IO as L-import qualified Data.Text.Lazy.Encoding as L-import qualified Data.ByteString.Lazy as BS-import qualified Codec.Compression.GZip as GZip-import qualified Codec.Archive.Tar as Tar import Text.XML.PolySoup-import Data.NKJP.Named+import qualified Data.Named.Graph as Nd+import qualified Data.Named.Tree as Nd+import qualified Text.NKJP.Tar as Tar+import qualified Text.NKJP.Morphosyntax as Mx +-- | A certainty of an annotator.+data Cert+ = High+ | Medium+ | Low+ deriving (Show)++-- | A pointer.+data Ptr t+ -- | Of #id form.+ = Local+ { target :: t }+ -- | Of loc#id form.+ | Global+ { target :: t+ , location :: t }+ deriving (Show, Functor)++-- | A derivation structure.+data Deriv t = Deriv+ { derivType :: t + , derivFrom :: t }+ deriving (Show, Functor)++-- | A paragraph.+data Para t = Para+ { paraID :: t+ , sentences :: [Sent t] }+ deriving (Show, Functor)++-- | A sentence.+data Sent t = Sent+ { sentID :: t+ , names :: [NE t] }+ deriving (Show, Functor)++-- | A segment element in a file. +data NE t = NE+ { neID :: t+ , derived :: Maybe (Deriv t)+ , neType :: t+ , subType :: Maybe t+ , orth :: t+ -- | Left base or Right when.+ , base :: Either t t+ , cert :: Cert+ , certComment :: Maybe t+ , ptrs :: [Ptr t] }+ deriving (Show)++instance Functor NE where+ fmap f NE{..} = NE+ { neID = f neID+ , derived = fmap (fmap f) derived+ , neType = f neType+ , subType = fmap f subType+ , orth = f orth+ , base = case base of+ Left x -> Left (f x)+ Right x -> Right (f x)+ , cert = cert+ , certComment = fmap f certComment+ , ptrs = map (fmap f) ptrs }++-- | Make NE forest from a segment list and a list of NEs, both lists+-- corresponding to the same sentence.+mkForest :: Ord t => [Mx.Seg t] -> [NE t]+ -> T.Forest (Either (NE t) (Mx.Seg t))+mkForest xs ns =+ Nd.mapForest decode (Nd.toForest graph)+ where+ -- Position of segment ID+ pos = (M.!) $ M.fromList (zip (map Mx.segID xs) [0..])+ -- Segment on the given position+ word = (M.!) $ M.fromList (zip [0..] xs)+ -- NE with given ID+ name = (M.!) $ M.fromList [(neID ne, ne) | ne <- ns]++ graph = Nd.mkGraph (0, length xs - 1)+ [ ( neID ne+ , map resolve (ptrs ne) )+ | ne <- ns ]++ resolve (Local ptr) = Left ptr+ resolve (Global ptr _) = Right (pos ptr)++ decode (Left neID) = Left (name neID)+ decode (Right k) = Right (word k)+ -- | TEI NKJP ann_morphosyntax parser. type P a = XmlParser L.Text a @@ -101,23 +206,28 @@ readNamed :: FilePath -> IO [Para L.Text] readNamed namedPath = parseNamed <$> L.readFile namedPath --- | Parse the NCP .tar.gz file.-readCorpus :: FilePath -> IO [(FilePath, [Para L.Text])]-readCorpus tarPath = do- map parseEntry . withBase "ann_named" <$> readTar tarPath--readTar :: FilePath -> IO [Tar.Entry]-readTar tar- = Tar.foldEntries (:) [] (error . show)- . Tar.read . GZip.decompress- <$> BS.readFile tar+-- | Parse all ann_named.xml files from the NCP .tar.gz file.+-- Directories will be processed in an ascending order (with+-- respect to directory names).+readCorpus :: FilePath -> IO [(FilePath, Maybe [Para L.Text])]+readCorpus = Tar.readCorpus "ann_named" parseNamed -parseEntry :: Tar.Entry -> (FilePath, [Para L.Text])-parseEntry entry =- (Tar.entryPath entry, parseNamed content)+-- | Parse the NCP .tar.gz corpus, extract all NEs and translate them+-- to the tree form using the 'mkForest' function. +readTrees :: FilePath -> IO [T.Forest (Either (NE L.Text) (Mx.Seg L.Text))]+readTrees path = do+ morph <- Mx.readCorpus path+ named <- readCorpus path+ return . concat $ map toTrees (sync morph named) where- (Tar.NormalFile binary _) = Tar.entryContent entry- content = L.decodeUtf8 binary+ toTrees (_, xs, ys) = map toForest $ zip+ (concatMap Mx.sentences xs)+ (concatMap sentences ys)+ toForest (x, y) = mkForest (Mx.segments x) (names y) -withBase :: String -> [Tar.Entry] -> [Tar.Entry]-withBase baseName = filter ((==baseName) . takeBaseName . Tar.entryPath)+sync :: [(FilePath, Maybe a)] -> [(FilePath, Maybe b)] -> [(FilePath, a, b)]+sync as bs =+ mapMaybe (uncurry just) (zip as bs)+ where+ just (dir, Just x) (_, Just y) = Just (dir, x, y)+ just _ _ = Nothing
+ Text/NKJP/Tar.hs view
@@ -0,0 +1,40 @@+module Text.NKJP.Tar+( readCorpus+) where++import Control.Applicative ((<$>), (<*>))+import System.FilePath (takeBaseName, takeDirectory)+import Data.List (groupBy, find)+import Data.Function (on)+import qualified Data.Text.Lazy as L+import qualified Data.Text.Lazy.Encoding as L+import qualified Codec.Compression.GZip as GZip+import qualified Codec.Archive.Tar as Tar+import qualified Data.ByteString.Lazy as BS++readTar :: FilePath -> IO [Tar.Entry]+readTar tar+ = Tar.foldEntries (:) [] (error . show)+ . Tar.read . GZip.decompress+ <$> BS.readFile tar++withBase :: String -> [Tar.Entry] -> Maybe Tar.Entry+withBase baseName = find ((==baseName) . takeBaseName . Tar.entryPath)++procContent :: (L.Text -> a) -> Tar.Entry -> a+procContent f entry =+ let (Tar.NormalFile binary _) = Tar.entryContent entry+ in f (L.decodeUtf8 binary)++-- | Visit each .tar directory and return (apart from the directory name)+-- processed contents of the entry with the given name or Nothing if such+-- entry doesn't exists in the directory.+readCorpus :: String -> (L.Text -> a) -> FilePath -> IO [(FilePath, Maybe a)]+readCorpus base f tarPath+ = map onGroup+ . groupBy ((==) `on` (takeDirectory . Tar.entryPath))+ <$> readTar tarPath+ where+ onGroup = (,)+ <$> takeDirectory . Tar.entryPath . head+ <*> (fmap (procContent f) . withBase base)
nkjp.cabal view
@@ -1,5 +1,5 @@ name: nkjp-version: 0.1.1+version: 0.2.0 synopsis: Manipulating the National Corpus of Polish (NKJP) description: The library provides parsing and printing utilities for the@@ -25,16 +25,22 @@ , zlib , tar >= 0.4 && < 0.5 , filepath- , data-named+ , data-named >= 0.4 && < 0.5 exposed-modules:- Data.NKJP.Morphosyntax- , Data.NKJP.Named- , Text.NKJP.Morphosyntax+ Text.NKJP.Morphosyntax , Text.NKJP.Named + other-modules:+ Text.NKJP.Tar+ ghc-options: -Wall source-repository head type: git location: git://github.com/kawu/nkjp.git++executable named2enamex+ hs-source-dirs: ., tools+ main-is: named2enamex.hs+ ghc-options: -Wall -O2
+ tools/named2enamex.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE OverloadedStrings #-}++import Control.Monad (forM_, (>=>))+import System.Environment (getArgs)+import Data.Maybe (catMaybes)+import qualified Data.Text as T+import qualified Data.Text.Lazy as L+import qualified Data.Text.Lazy.IO as L++import Data.Named.Tree+import Text.Named.Enamex (showForest)+import qualified Text.NKJP.Named as Ne+import qualified Text.NKJP.Morphosyntax as Mx++neType :: Ne.NE L.Text -> T.Text+neType ne = L.toStrict . L.intercalate "." . catMaybes . map ($ ne) $+ [ Just . Ne.neType+ , Ne.subType+ , Ne.derived >=> return . Ne.derivType ]++orth :: Mx.Seg L.Text -> T.Text+orth = L.toStrict . Mx.orth++main :: IO ()+main = do+ [teiPath] <- getArgs+ fs <- Ne.readTrees teiPath+ forM_ fs $ \ts ->+ L.putStrLn . showForest . mapForest (onEither neType orth) $ ts