文字列からの情報抽出
Posted feedbacks - Haskell
良く分かりませんでした。 取り合えずparsecの練習で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | module Main where
import System
import Char
import Text.ParserCombinators.Parsec hiding (spaces)
import Monad
import Control.Monad.Error
import IO hiding (try)
main = readFile "a.txt" >>= pp >>= print >> return ()
pp s = case parse (many $try(wordx)<|>other) "lisp" s of
(Right x) -> return $filter okparse x
(Left x) -> error "error"
okparse ("",_,_,_) = False
okparse (_,_,_,_)= True
w = many1 letter
hi = do _ <- char '-'
x <- string "hidden"
return x
sz = do _ <- char '-'
x <- try(string "big") <|> string "small"
return x
wordx = do x <- w
(y, z) <- (do yy <-try (hi)
zz <-option "" sz
return (yy,zz))
<|>
(do zz<- option "" sz
return ("", zz))
char '.'
ext <- w
return (x,y,z, ext)
other = do x <- noneOf ""
return ("", "","","")
|
個人的はProgramming Policyにより、正規表現は封印中 でもParsec は使い方を思い出すのがちょっと面倒ね。 ということで。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import Data.Char
import Text.ParserCombinators.ReadP
type Name = String
type Size = String
type Hidden = Bool
type Info = (Name,Name,Size,Hidden)
pName :: ReadP Name
pName = munch1 isAlpha
pSize :: ReadP Size
pSize = (string "-big" >> return "big")
+++ (string "-small" >> return "small")
+++ (return "normal")
pHidden :: ReadP Hidden
pHidden = (string "-hidden" >> return True)
+++ (return False)
pExt :: ReadP Name
pExt = char '.' >> pName
pInfo :: ReadP Info
pInfo = do { name <- pName
; size <- pSize
; hidden <- pHidden
; ext <- pExt
; return (name,ext,size,hidden)
}
showInfo :: Info -> String
showInfo (name,ext,size,hidden)
= "name:'"++name++"', ext:'"++ext++", size: "++size++" hidden: "++show hidden
readInfo :: ReadS Info
readInfo = readP_to_S pInfo
infoReader :: String -> [Info]
infoReader [] = []
infoReader ccs@(c:cs) = case readInfo ccs of
[] -> infoReader cs
(info,rs):_ -> info : infoReader rs
main :: IO ()
main = test
test :: IO ()
test = putStr $ unlines $ map showInfo $ infoReader $ testdata
testdata = unlines
["aaa abc-hidden.png>hoge-big.jpeg"
,"---foo-hidden-small.gif|^_^a.bmp"
,"--hiddena-hoge.png<=not hidden~~"
,"--small.jpg<=not small(^_^)"
,"normal-small-big.hoge"]
{- 実行例
*Main> :main
name:'abc', ext:'png, size: normal hidden: True
name:'hoge', ext:'jpeg, size: big hidden: False
name:'hidden', ext:'gif, size: small hidden: False
name:'a', ext:'bmp, size: normal hidden: False
name:'hoge', ext:'png, size: normal hidden: False
name:'small', ext:'jpg, size: normal hidden: False
name:'small', ext:'hoge, size: big hidden: False
-}
|
文字列からパターンにマッチする表現のデータをとりだしたり, 特定のパターンにマッチする表現を別の表現で置換したり, というのが正規表現の使いどころなんだね. (という自明なことに今さら気づきました.^^;) とするとパターンを指定するのは正規表現ではなくて,たとえばもうすこし 拡張してパーザで指定してもいいわけですよね.(これも自明か^^;) たとえば,ReadP a が一般化されたパターンを表すと思えばいいわけでよね... そうすると性能の問題はあるにせよ、 一般化したパターンをもらって,(雑音のある)文字列からデータを取り出す関数を 生成する関数 reader とか,パターン(とデータを文字列に変換する関数)をもらって 文字列のなかの部分列を置換する関数を生成する関数 replacer とかがあれば汎用性 があるはずですよねぇ.(正規表現はまさにこのように使うのでしょうから) そうすると先に投稿したコードでは infoReader の定義は infoReader = reader pInfo となるし,たとえば入力文字列からデータ部分をとりのぞいて雑音部分だけに してしまうにような infoNoise は infoNoise = replacer pInfo (const "") なんてことができますね. *Main> let infoNoise = replacer pInfo (const "") *Main> infoNoise testdata "aaa >\n---foo-|^_^\n--hiddena-<=not hidden~~\n--<=not small(^_^)\nnormal-\n"
1 2 3 4 5 6 7 8 9 10 11 12 13 | reader :: ReadP a -> (String -> [a])
reader parser string = case string of
"" -> []
_ -> case readP_to_S parser string of
[] -> reader parser (tail string)
(a,string'):_ -> a : reader parser string'
replacer :: ReadP a -> (a -> String) -> String -> String
replacer p s str = case str of
"" -> ""
_ -> case readP_to_S p str of
[] -> head str : replacer p s (tail str)
(a,str'):_ -> s a ++ replacer p s str'
|
とりあえずサンプルはできた感じです。多分。 *Main> :!cat sample.txt aaa abc-hidden.png>hoge-big.jpeg ---foo-hidden-small.gif|^_^a.bmp --hiddena-hoge.png<=not hidden~~ --small.jpg<=not small(^_^) normal-small-big.hoge *Main> *Main> :main sample.txt name:'abc', ext:'png', size: normal hidden: True name:'hoge', ext:'jpeg', size: big hidden: False name:'foo', ext:'gif', size: small hidden: True name:'a', ext:'bmp', size: normal hidden: False name:'hoge', ext:'png', size: normal hidden: False name:'small', ext:'jpg', size: normal hidden: False name:'small', ext:'hoge', size: big hidden: False
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | import System (getArgs)
import Control.Monad (liftM)
import Text.ParserCombinators.Parsec
data Val = V {name :: String, ext :: String, hidden :: String, size :: String} | None deriving Eq
instance Show Val where
show (V n e h s) = "name:'" ++ n ++ "', ext:'" ++ e ++ "', size: " ++ s ++ " hidden: " ++ h
show None = ""
alpha = ['a'..'z'] ++ ['A'..'Z']
nameParser :: GenParser Char () String
nameParser = many1 (oneOf alpha)
extParser :: GenParser Char () String
extParser = char '.' >> many1 (oneOf alpha)
hiddenParser :: GenParser Char () String
hiddenParser = try ((string "-hidden") >> return "True") <|> return "False"
sizeParser :: GenParser Char () String
sizeParser = try (string "-small" >> return "small")
<|> try (string "-big" >> return "big")
<|> return "normal"
expression :: GenParser Char () Val
expression = do
n <- nameParser
h <- hiddenParser
s <- sizeParser
e <- extParser
return $ V n e h s
skip :: GenParser Char () Val
skip = manyTill (many1 (oneOf alpha)) (many1 (noneOf alpha)) >> return None
expressionParser :: GenParser Char () [Val]
expressionParser = do
exp <- try expression <|> skip
exps <- try expressionParser <|> return []
return $ exp:exps
run :: String -> Either ParseError [Val]
run = parse expressionParser ""
main = do
s <- liftM run . readFile . head =<< getArgs
case s of
Left e -> print e
Right x -> mapM_ print $ filter (/= None) x
|
汚い。
1 2 3 4 5 6 7 8 9 10 11 12 | import Control.Monad
import Data.Char
import System.Environment
import Text.ParserCombinators.Parsec
main = getArgs >>= parseFromFile allInfo . head >>= \(Right i) -> mapM_ (putStrLn . showInfo) i
showInfo [n,h,s,e] = "name:'" ++ n ++ "', ext:'"++ e ++"', size: "++ s ++" hidden: " ++ h
allInfo = liftM (filter (not.null)) (manyTill (try info <|> skip) eof)
skip = many letter >> many (satisfy (not.isAlpha)) >> return []
info = sequence [many1 letter, hidden, size, char '.' >> many1 letter]
hidden = liftM (show.not.null) (option "" (try (string "-hidden")))
size = (char '-' >> (string "big" <|> string "small")) <|> return "normal"
|





にしお
#3407()
Rating0/0=0.00
サンプル入力
サンプル出力
探すべき文字列は下の条件を満たします
出力は以下の条件を満たす必要があります
このお題は、正規表現のグループに名前をつけて連想配列として取得できるPythonからの挑戦状です。
[ reply ]