1-6章は既にPLEAC-Haskellにあるのでそちらを参照してください。
もとのレシピ(perl)はPLEACを参照のこと
openFileを使う
import System.Environment
main = do
(file:_) <- getArgs
h <- openFile file ReadMode
できるのか?
getpwnamがみつからなかったので書いた。
import Data.List.Split
import Control.Applicative
import Text.Regex
import System.Environment
getpwnam username = do
passwds <- map (splitOn ":") <$> lines <$> readFile "/etc/passwd"
return (filter (\line -> (line!!0)==username) passwds)
main :: IO ()
main = do
(path:_) <- getArgs
case matchRegexAll (mkRegex "^~([^/]*)") path of
Nothing -> putStrLn path
Just (_,uhome,subdir,cs) ->
if length cs == 1 && length (cs!!0) /= 0
then do
dir <- getpwnam (cs!!0)
if (length dir) == 1
then putStrLn $ ((dir!!0)!!5) ++ subdir
else putStrLn $ "Error: " ++ uhome ++ " not found"
else do
homedir <- lookup "HOME" <$> getEnvironment
case homedir of
Just home -> putStrLn $ home ++ subdir
Nothing -> putStrLn "Error: Env[HOME] not found"
Making Perl Report Filenames in Errors
エラーの内容を出力してないのでこれは駄目だな
import System.Environment
import Control.Exception
import Prelude hiding (catch)
import System.Exit
main = do
(file:_) <- getArgs
catch (putStr =<< readFile file) $
\e -> return (e::SomeException) >> print ("Error on reading file: " ++ file)
openTempFile を使う
import System.Environment
import System.IO
main :: IO ()
main = do
(dir:prefix:_) <- getArgs
(filePath,h) <- openTempFile dir prefix
putStrLn filePath
Reading Lines with Continuation Characters
もとのレシピは行ごとに読んで末尾にバックスラッシュついてるかチェックし てるのだけど、書いたコードは\\nを探して無視するようになっている。
import System.Environment
ccappend :: String -> String
ccappend [] = []
ccappend (c:[]) = [c]
ccappend (c1:c2:cs)
| c1 == '\\' && c2 == '\n' = ccappend (cs)
| otherwise = c1:ccappend (c2:cs)
main = do
args <- getArgs
content <- readFile (args!!0)
putStr $ ccappend content
Counting Lines (or Paragraphs or Records) in a File
applicative
countlines = (length . lines) <$> readFile
Monad
countlines = liftM (length . lines) $ readFile
Processing Every Word in a File
words関数で単語のリストに分解してmapすればいい。
import System.Environment
main = do
args <- getArgs
content <- readFile (args!!0)
print $ words content
Reading a File Backwards by Line or Paragraph
reverseする
import System.Environment
main = do
args <- getArgs
content <- readFile (args!!0)
print $ reverse . lines $ content
ファイルハンドルがEOFだったらthreadDelayで一秒待ってループ。そうじゃな かったら文字を読み込んで出力
import System.IO
import System.Environment
import Control.Concurrent
main = do
args <- getArgs
h <- openFile (args!!0) ReadMode
loop h
where loop h = do
end <- hIsEOF h
if end then (threadDelay 1000000) >> loop h
else do
c <- hGetChar h
putChar c
hFlush stdout
loop h
Picking a Random Line from a File
一行をランダムに取り出す。アルゴリズムはよく知られたやつ。
import System.Environment
import System.Random
import Control.Applicative
randomNumGen :: Int -> IO Int
randomNumGen n = getStdRandom (randomR (0, n))
choiceLine :: String -> [(Int, String)] -> IO String
choiceLine s [] = return s
choiceLine s ((n, line):cs) = do
n' <- randomNumGen n
if n' < 1 then choiceLine line cs
else choiceLine s cs
main :: IO ()
main = do
args <- getArgs
choiced <- choiceLine "" =<< zip [1..] <$> lines <$> readFile (args!!0)
putStrLn choiced
import System.Environment
import System.Random.Shuffle
import Control.Applicative
main :: IO ()
main = do
args <- getArgs
shuffled <- shuffleM =<< lines <$> readFile (args!!0)
mapM_ putStrLn shuffled
Reading a Particular Line in a File
import System.Environment
import Control.Applicative
main :: IO ()
main = do
(file:lineNum:_) <- getArgs
line <- flip (!!) (pred (read lineNum :: Int)) . lines <$> readFile file
putStrLn line
Processing Variable-Length Text Fields
Text.RegexのsplitRegex を使えばいい
import Text.Regex
splitRegex (mkRegex "\tb") "a\tba\tba\tbab" -- ["a","a","a","ab"]
Removing the Last Line of a File
import System.Environment
import Control.Applicative
main :: IO ()
main = do
(file:_) <- getArgs
lastElimLines <- (init . lines) <$> readFile file
mapM_ putStrLn lastElimLines
hSeekをつかう
import System.IO
import System.Environment
main = do
(file:num:_) <- getArgs
h <- openFile file ReadMode
hSeek h AbsoluteSeek (read num :: Integer)
c <- hGetChar h
putChar c
Getting and Setting Timestamps
時間の変換がちょっと面倒だ。
import System.Posix.Files
import System.Time
import System.Posix.Types
import System.Environment
getTimes :: FilePath -> IO (ClockTime, ClockTime)
getTimes fp =
do stat <- getFileStatus fp
return (toct (accessTime stat),
toct (modificationTime stat))
toct :: EpochTime -> ClockTime
toct et = TOD (truncate (toRational et)) 0
main :: IO ()
main = do
(file:_) <- getArgs
(atime, mtime) <- getTimes file
toCalendarTime atime >>= print
toCalendarTime mtime >>= print
参考
Processing All Files in a Directory
System.DiirectorygetDirectoryContentsをつかう
Globbing, or Getting a List of Filenames Matching a Pattern
Glob packageを使えばいい
Processing All Files in a Directory Recursively
ライブラリにはみつからないがRWHに書いてある
Removing a Directory and Its Contents
System.DiirectoryのremoveDirectoryRecursiveを使う
省略
省略
省略
標準ライブラリがあるのでそれを使えばいい。
Prelude> :m Network.BSD Network.Socket
Prelude Network.Socket Network.BSD> getHostByName "google.co.jp" >>= print . hostAddresses
[3102440778,3085663562,3219881290]
Prelude Network.Socket Network.BSD Control.Monad> mapM inet_ntoa =<< liftM hostAddresses (getHostByName "google.co.jp")
["173.194.38.95","173.194.38.88","173.194.38.87"]
Prelude Network.Socket Network.BSD> inet_addr "74.125.235.184" >>= getHostByAddr AF_INET
HostEntry {hostName = "nrt19s12-in-f24.1e100.net",
hostAliases = ["184.235.125.74.in-addr.arpa"],
hostFamily = AF_INET, hostAddresses = [3102440778]
}
Prelude> :m Network.FTP.Client
Prelude Network.FTP.Client> loginAnon h
(230,["Login successful."])
Prelude Network.FTP.Client> cwd h "/pub/linux/kernel/Historic"
(250,["Directory successfully changed."])
Prelude Network.FTP.Client> nlst h Nothing >>= putStrLn . unlines
linux-0.01.tar.gz
linux-0.01.tar.gz.sign
linux-0.01.tar.sign
old-versions
v0.99
Prelude Network.FTP.Client> getbinary h "linux-0.01.tar.gz.sign" >>= putStrLn . fst
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.0 (GNU/Linux)
Comment: See http://www.kernel.org/signature.html for info
iD8DBQA54rf0yGugalF9Dw4RAqelAJ9lafFni4f/QyJ2IqDXzW2nz/ZIogCfRPtg
uYpWffOhkyByfhUt8Lcelec=
=KnLA
-----END PGP SIGNATURE-----