nanq-1.0.0: nanq.hs
import Data.Kanji
import Data.List (delete, nub)
import Data.Maybe (fromJust)
import System.Console.GetOpt
import System.Environment (getArgs)
import System.IO (hGetContents, stdin)
import Text.Printf (printf)
---
data Language = Jap | Eng deriving (Show,Eq)
data Flag = FileInput | PipeInput | Help | Average |
Unknowns | LevelDist | KDensity | Elementary |
Text | JapOutput | AllFromQ Rank deriving (Show,Eq)
options :: [OptDescr Flag]
options = [ Option ['f'] ["file"] (NoArg FileInput) fDesc
, Option ['p'] ["pipe"] (NoArg PipeInput) pDesc
, Option ['h'] ["help"] (NoArg Help) hDesc
, Option ['a'] ["average"] (NoArg Average) aDesc
, Option ['u'] ["unknowns"] (NoArg Unknowns) uDesc
, Option ['d'] ["leveldist"] (NoArg LevelDist) lDesc
, Option ['k'] ["density"] (NoArg KDensity) kDesc
, Option ['e'] ["elementary"] (NoArg Elementary) eDesc
, Option ['t'] ["text"] (NoArg Text) tDesc
, Option ['j'] ["japanese"] (NoArg JapOutput) jDesc
, Option ['q'] ["fromq"]
(ReqArg (\s -> AllFromQ (read s :: Rank)) "Rank") qDesc
]
where fDesc = "Takes input from a given file." ++
"\n入力は指定のファイルから"
pDesc = "Takes input from a pipe (stdin)." ++
"\n入力はpipe (つまりstdin)から"
hDesc = "Shows this help message." ++
"\nこのメッセージから出力"
aDesc = "Find the average level of some given line of Japanese." ++
"\n日本語の文の平均的な級を求める"
uDesc = "Report Kanji whose Level could not be determined." ++
"\n級を明確にできなかった漢字を報告"
lDesc = "Find the % distribution of levels in given Japanese." ++
"\nどの級の漢字がどれ程出ているか、パーセントで出力"
kDesc = "Determines how much of the input is made of Kanji." ++
"\n入力は何パーセント漢字でできているか出力"
eDesc = "Determines how much of the input is made of Kanji" ++
"\nlearnt in Elementary School in Japan." ++
"\n入力は何パーセント小学校で習う漢字でできているか出力"
tDesc = "Applies -k -e and -d all at once to analyse some text." ++
"\n-k、-e、-dを連続に使って入力を分析"
jDesc = "Output is given in Japanese instead of English." ++
"\n出力の際は日本語"
qDesc = "Filters out all but Kanji from the requested Level." ++
"\n指定された級の漢字だけ出力"
usageMsg :: String
usageMsg = "Usage : nanq [OPTION] (kanji / file)"
japQNames :: [(Rank,String)]
japQNames = zip rankNums ["10級","9級","8級","7級","6級","5級","4級",
"3級", "準2級","2級","準1級","1級"]
engQNames :: [(Rank,String)]
engQNames = zip rankNums ["Tenth Level","Ninth Level","Eighth Level",
"Seventh Level","Sixth Level","Fifth Level",
"Forth Level","Third Level", "Pre-Second Level",
"Second Level","Pre-First Level","First Level"]
findAverageQ :: Language -> [Char] -> String
findAverageQ lang ks =
printf (getMsg lang ++ "%.2f") . averageLevel levels . asKanji $ ks
where getMsg Eng = "Average Level: "
getMsg Jap = "平均の級:"
findQs :: Language -> [Char] -> [String]
findQs lang ks = map (nanQ lang) $ asKanji ks
nanQ :: Language -> Kanji -> String
nanQ lang k = maybe (bad lang) (good lang . _rank) $ level levels k
where
good Eng n = (show k) ++ " is " ++ (articledQName n) ++ " Kanji."
good Jap n = "「" ++ (show k) ++ "」は" ++ (jQName n) ++ "の漢字"
bad Eng = (show k) ++ " is not in any level."
bad Jap = "「" ++ (show k) ++ "」はどの級の漢字でもない"
articledQName n = getArticle (eQName n) ++ " " ++ eQName n
getArticle name = if head name `elem` "AEIOU" then "an" else "a"
eQName n = getQName n engQNames
jQName n = getQName n japQNames
getQName n names = fromJust $ n `lookup` names
findUnknowns :: Language -> String -> [String]
findUnknowns lang ks = case unknowns of
[] -> [bad lang]
_ -> good lang : map show unknowns
where unknowns = nub . filter (not . hasLevel levels) . asKanji $ ks
bad Eng = "No Kanji of unknown Level found."
bad Jap = "級を明確にできない漢字は見つからなかった"
good Eng = "The following Kanji of unknown Level were found:"
good Jap = "級を明確にできなかった漢字は:"
findDistribution :: Language -> String -> [String]
findDistribution lang ks =
map (\(name,per) -> printf "%4s: %05.2f%%" name per) namePercentPairs
where namePercentPairs = map rawToPretty distributions
distributions = levelDist levels $ asKanji ks
rawToPretty (qn,p) = (getQName lang qn, p * 100)
getQName Eng qn = getName engQNames "Above Second Level" qn
getQName Jap qn = getName japQNames "2級以上" qn
getName names msg qn = maybe msg id $ qn `lookup` names
howMuchIsKanji :: Language -> String -> String
howMuchIsKanji lang ks = printf "%s: %.2f%%" (getMsg lang) percent
where percent = 100 * kanjiDensity ks
getMsg Eng = "Kanji Density"
getMsg Jap = "漢字率"
howMuchIsElementaryKanji :: Language -> String -> String
howMuchIsElementaryKanji lang ks = printf (getMsg lang) percent
where percent = 100 * elementaryKanjiDensity ks
getMsg Eng = "Input Kanji is %.2f%% Elementary School Kanji."
getMsg Jap = "入力した漢字は「%.2f%%」小学校で習う漢字。"
getAllFromLevel :: Rank -> [Char] -> [Kanji]
getAllFromLevel qn ks = maybe [] f $ levelFromRank levels qn
where f q = nub . filter (isKanjiInLevel q) . asKanji $ ks
parseOpts :: [String] -> IO ([Flag],[String])
parseOpts args = case getOpt Permute options args of
(opts,nonopts,[]) -> return (opts,nonopts)
(_,_,_) -> argError "Bad flag used."
-- Determine input source and output language.
cleanOpts :: ([Flag],[String]) -> IO ([Flag],Language,String)
cleanOpts (opts,nonopts) = clean opts nonopts Eng -- English by default.
where clean opts nonopts lang
| JapOutput `elem` opts = clean (without JapOutput) nonopts Jap
| Help `elem` opts = return ([Help],lang,"")
| PipeInput `elem` opts = do input <- hGetContents stdin
return (without PipeInput,lang,input)
| null nonopts = argError "No Kanji / file given!"
| FileInput `elem` opts = do input <- readFile $ head nonopts
return (without FileInput,lang,input)
| otherwise = return (opts,lang,head nonopts)
where without x = delete x opts
executeOpts :: ([Flag],Language,String) -> IO ()
executeOpts (flags,lang,input) =
case flags of
[Help] -> putStr $ usageInfo usageMsg options
[Average] -> putStrLn $ findAverageQ lang input
[] -> mapM_ putStrLn $ findQs lang input
[Unknowns] -> mapM_ putStrLn $ findUnknowns lang input
[LevelDist] -> mapM_ putStrLn $ findDistribution lang input
[KDensity] -> putStrLn $ howMuchIsKanji lang input
[Elementary] -> putStrLn $ howMuchIsElementaryKanji lang input
[Text] -> mapM_ execAll [KDensity,Elementary,LevelDist]
[AllFromQ qn] -> mapM_ print $ getAllFromLevel qn input
_ -> argError "Conflicting flags given."
where execAll flag = executeOpts ([flag],lang,input) >> putStrLn ""
argError :: String -> a
argError msg = error $ usageInfo (msg ++ "\n" ++ usageMsg) options
main :: IO ()
main = do
args <- getArgs
opts <- parseOpts args
cleanedOpts <- cleanOpts opts
executeOpts cleanedOpts