or1ko's diary

日々を書きます

24

言語処理100本ノック 2015

24. ファイル参照の抽出
記事から参照されているメディアファイルをすべて抜き出せ.

メディアファイルというのが何を指しているのかわからなかったが、
ファイル参照の抽出というタイトルから、File:を抜き出すことにした。
中身を見ていると、日本語のファイルでも良さそうだったが、面倒だったためFileのみとした。

import Data.Aeson as A
import Control.Applicative
import System.Environment
import Data.Maybe
import Data.ByteString.Lazy.UTF8 as B
import GHC.Generics
import Text.Regex.Posix
import Prelude as P
import GHC.IO.Encoding

data Article = Article {
  text :: String,
  title :: String
} deriving (Eq, Show, Generic)
instance FromJSON Article

main = do
  setLocaleEncoding utf8
  filename <- head <$> getArgs
  body <- fromString <$> readFile filename
  writeFile "24.out.txt" $ unlines $ map (P.drop 5) $ filter (\x -> P.length x /= 0 ) $ concatMap concat $ map f $ map (text . fromJust . A.decode) $ B.lines $ body 
  where
    f = ((=~ ("File:[^]|]*" :: String)) :: String -> [[String]]) 

[^]|]と[^|]]で異なる解釈となることが勉強になった。

Windows版HaskellでUTF8のファイル読み書き

Haskell Platform 7.10.2-aをインストールした際に、日本語(utf8)の扱いがわからなくなってしまって、ずっとほっといたのだが、ふと思い出して調べてみた。


紆余曲折したが、ポイントとしては下記の2点。

  • Handleにutf8を指定

ファイルの読み書きなどのデフォルトのエンコーディングがcp932になっているため、utf8のファイルを読み込む場合は、Handleのエンコーディングをutf8に変更する

  • ByteStringを扱う場合は、utf8-stringモジュールを使う

ただし、Stringで読みこんだ文字列をByteStringに変換して使う。標準でインストールされるByteStringモジュールに存在するreadFileなどの関数がないため。

サンプルとして、第一引数で指定したファイルをutf8の文字コードで読み込み、内容を標準出力するプログラムを記載する。

import System.Environment
import System.IO

main = do
          filename <- head <$> getArgs 
          withFile filename ReadMode f 
          where
            f h = hSetEncoding h utf8 >> hGetContents h >>= putStrLn

また、Powershellから標準出力をrunghcに渡す場合、下記のコマンドを実行する。

$OutputEncoding = [Text.Encoding]::Default

コマンドに渡す際のエンコーディングがasciiになっているため、cp932に変更する。

毎回ハンドルのエンコーディングを変更するのは面倒だという場合は、
GHC.IO.EncodingのsetLocaleEncoding関数で、デフォルト値を変更することができる。ただし、標準出力などのエンコーディングも変更されるので、注意する。

Haskell Platform 7.10.2-a

Haskellのライブラリのブックマークがたどれなくなっていたので、
haskell.orgを見に行ったら、Haskell Platformが新しくなっていた。
以前、2014うんちゃらというのを使っていたので、7とは何事だろうか...。

23

言語処理100本ノック 2015

23. セクション構造
記事中に含まれるセクション名とそのレベル(例えば"== セクション名 =="なら1)を表示せよ

23.hs

{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

import Data.Aeson as A
import Control.Applicative
import System.IO.UTF8 as I8
import System.Environment
import Data.Maybe
import Data.ByteString.Lazy.UTF8 as B
import GHC.Generics
import Text.Regex.Posix
import Prelude as P

data Article = Article {
  text :: String,
  title :: String
} deriving (Eq, Show, Generic)
instance FromJSON Article

main = do
  filename <- head <$> getArgs
  body <- fromString <$> I8.readFile filename
  I8.writeFile "23.txt" $ unlines $ map f $ filter isHeadline $ concatMap P.lines $ map (text . fromJust . A.decode) $ B.lines $ body 
    where
      f x = headline x ++ "," ++ depth x 
      isHeadline = ((=~ ("^={2,6}.*={2,6}" :: String)) :: String -> Bool)
      headline = filter (\x -> (x /= ' ') && (x /= '='))
      depth = show . P.length . ((=~ ("=+" :: String)) :: String -> String)

22

言語処理100本ノック 2015

22. カテゴリ名の抽出
記事のカテゴリ名を(行単位ではなく名前で)抽出せよ.

22.hs

{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

import Data.Aeson as A
import Control.Applicative
import System.IO.UTF8 as I8
import System.Environment
import Data.Maybe
import Data.ByteString.Lazy.UTF8 as B
import GHC.Generics
import Text.Regex.Posix
import Prelude as P

data Article = Article {
  text :: String,
  title :: String
} deriving (Eq, Show, Generic)
instance FromJSON Article

main = do
  filename <- head <$> getArgs
  body <- fromString <$> I8.readFile filename
  I8.writeFile "22.txt" $ unlines $ map f2 $ filter f $ concatMap P.lines $ map (text . fromJust . A.decode) $ B.lines $ body 
    where
      f = ((=~ ("^[[][[]:?(カテゴリ|Category):" :: String)) :: String -> Bool)
      f2 = tail . ((=~ (":[^]|]*" :: String)) :: String -> String)

21

言語処理100本ノック 2015

21. カテゴリ名を含む行を抽出
記事中でカテゴリ名を宣言している行を抽出せよ.

21.hs

{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

import Data.Aeson as A
import Control.Applicative
import System.IO.UTF8 as I8
import System.Environment
import Data.Maybe
import Data.ByteString.Lazy.UTF8 as B
import GHC.Generics
import Text.Regex.Posix
import Prelude as P

data Article = Article {
  text :: String,
  title :: String
} deriving (Eq, Show, Generic)
instance FromJSON Article

main = do
  filename <- head <$> getArgs
  body <- fromString <$> I8.readFile filename
  I8.writeFile "21.txt" $ unlines $ filter (\x -> x =~ ("^[[][[]:?(カテゴリ|Category)" :: String) :: Bool) $ concatMap P.lines $ map (text . fromJust . A.decode) $ B.lines $ body

ヘルプ:Wiki マークアップ早見表 - WordPress Codex 日本語版

wikipediaの記法では、日本語の「カテゴリ」を許可しているのかわからなかったが、いくつかあるみたいだったので、抽出した。