シェル芸勉強会に対して自ら敢えてHaskellで他流試合を申し込む
Mon Dec 23 11:55:54 JST 2013 (modified: Fri Sep 29 21:38:45 JST 2017)
views: 1499, keywords:CLI,Haskell,USP友の会,シェル芸,シェル芸勉強会 この記事は最終更新日が7年以上前のものです。
昨日のシェル芸勉強会に対して、自分で喧嘩を売ってみます。書きなぐりのHaskellコードです。問題はコチラ↓。
Q1(データのフリップ)
uedamac:tmp ueda$ cat q1.hs
main = getContents >>= putStrLn. unwords . f . words
f [] = []
f (a:b:c) = [b,a] ++ f c
uedamac:tmp ueda$ echo {1..10} | ./q1
2 1 4 3 6 5 8 7 10 9
Q2(文字列の個数カウント)
uedamac:tmp ueda$ cat q2.hs
main = getContents >>= print . g. (Count 0 0 0 0)
data Count = Count Int Int Int Int String deriving Show
g (Count a b c d []) = Count a b c d []
g (Count a b c d ('ユ':'ニ':'ケ':'ー':'ジ':str)) = g (Count (a+1) b c d str)
g (Count a b c d ('ユ':'ニ':'ゲ':'ー':'ジ':str)) = g (Count a (b+1) c d str)
g (Count a b c d ('U':'S':'P':str)) = g (Count a b (c+1) d str)
g (Count a b c d ('U':'P':'S':str)) = g (Count a b c (d+1) str)
g (Count a b c d (_:str)) = g (Count a b c d str)
uedamac:tmp ueda$ echo ユニゲージユニケージユニゲージUSP友の会USP友の会UPS友の会UPS友の会 | ./q2
Count 1 2 2 2 ""
Q3(一致するファイルの検出)
uedamac:tmp ueda$ cat q3.hs
main = do a <- readFile "file1"
b <- readFile "file2"
c <- readFile "file3"
d <- readFile "file4"
g [("file1",a),("file2",b),("file3",c),("file4",d)]
g [] = return ()
g (a:ds) = f a ds >> g ds
f a ds = putStrLn $ concat $ map (h a) ds
h (f1,a) (f2,b) = if a == b then unwords [f1,f2] else []
uedamac:tmp ueda$ ./q3
file1 file3
Q4(変則ソート)
uedamac:tmp ueda$ cat q4.hs
main = getContents >>= print . f. map (\\x -> read x :: Int) . words
f ns = odd ++ eve
where odd = filter (\\x -> x `mod` 2 == 0) ns
eve = filter (\\x -> x `mod` 2 == 1) ns
uedamac:tmp ueda$ echo 3 8 2 10 1 8 9 | ./q4
8,2,10,8,3,1,9] [
Q5(ランレングス圧縮の一種)
uedamac:tmp ueda$ cat q5.hs
main = getContents >>= putStrLn . unwords . f . filter (\\x -> x == '0' || x == '1')
f (a:ss) = f' (a:ss) a
f' [] _ = []
f' str a = (a:lng) : f' (dropWhile (== a) str) c
where b = length $ takeWhile (== a) str
c = if a == '0' then '1' else '0'
lng = if b == 1 then "" else show b
uedamac:tmp ueda$ echo 000001111111111001010 | ./q5
05 110 02 1 0 1 0
Q6(連続した数字の省略)
uedamac:tmp ueda$ cat q6.hs
import Data.List.Split
main = getContents >>= putStrLn . unwords . g . splitWhen (== -1). f . map (\\x -> read x :: Int) . words
f (a:b:[]) = if a+1 == b then [a,b] else [a,-1,b]
f (a:b:ns) = if a+1 == b then a : f (b:ns) else [a,-1] ++ f (b:ns)
g [] = []
g (a:as) = h a : g as
h as = if a == b then a else a ++ "-" ++ b
where a = show $ head as
b = show $ last as
uedamac:tmp ueda$ echo 1 2 3 5 6 8 10 11 12 15 | ./q6
1-3 5-6 8 10-12 15
Q7(パスワード破り)
uedamac:tmp ueda$ cat q7.hs
import Data.Digest.Pure.MD5
import qualified Data.ByteString.Lazy.Char8 as B
main = g $ f [000..999]
g [] = return ()
g ((n,a):as) = (if t `B.isPrefixOf` aa then print n else return () ) >> g as
where t = B.pack "250"
aa = B.pack $ show a
f [] = []
f (n:ns)
| n < 10 = (n,(md5 $ B.pack ("00" ++ (show n)))) : f ns
| n < 100 = (n,(md5 $ B.pack ("0" ++ (show n)))) : f ns
| otherwise = (n,(md5 $ B.pack (show n))) : f ns
uedamac:tmp ueda$ ./q7
456
Q8(しりとり)
sort -R はインチキっぽいが、ソートしなくても一応できるので・・・
uedamac:tmp ueda$ cat q8.hs
main = getContents >>= putStrLn . unlines . f. f. f . lines
f [] = []
f (a:[]) = []
f (a:b:lns)
| last a == head b = (a ++ "->" ++ b) : f lns
| otherwise = f lns
uedamac:tmp ueda$ gsort -R /usr/share/dict/words | ./q8
rhombogenic->cattiness->sarkar->rhamnaceous->swishing->geneticism->ministryship->pleonastical
できた〜〜〜〜!!!けどやっぱりシェルワンライナーの方が気楽だ・・・