 Haskell Quiz/IP to Country/Solution Dolio - Revision history 2017-02-19T15:07:54Z Revision history for this page on the wiki MediaWiki 1.19.14+dfsg-1 Dolio: creation 2007-09-19T04:04:20Z <p>creation</p> <p><b>New page</b></p><div>[[Category:Haskell Quiz solutions|IP to Country]]<br /> <br />).<br /> <br />. :)<br /> <br /> This just processes the raw file downloaded from the website linked in the quiz, and processes it linearly. One could probably devise an optimized version of the database, or a more efficient searching scheme and gain performance, but the naive solution is still plenty fast.<br /> <br /> <haskell><br /> {-# LANGUAGE PatternGuards #-}<br /> <br /> module Main(main) where<br /> <br /> import Data.Maybe<br /> import System.Environment<br /> <br /> import qualified Data.ByteString.Char8 as B<br /> import qualified Data.ByteString.Lazy.Char8 as L<br /> <br /> -- Process a file by line. For each line in the file denoted by<br /> -- the FilePath, the function is called. If the result of the<br /> -- computation is True, processing is cut off early.<br /> --<br /> -- This uses lazy chunked reading, but operates on the chunks<br /> -- one by one for (hopefully) maximum speed.<br /> processFile :: FilePath -> (B.ByteString -> IO Bool) -> IO ()<br /> processFile path op = proc . L.toChunks =<< L.readFile path<br /> where<br /> proc [] = return ()<br /> proc [c] = proc' (B.lines c) >> return ()<br /> proc (c:cc:cs) = do b <- proc' (B.lines c')<br /> if b then return () else proc cs'<br /> where (c', t) = B.breakEnd (=='\n') c<br /> cs' = B.append t cc : cs<br /> proc' [] = return False<br /> proc' (x:xs) = do b <- op x<br /> if b then return True else proc' xs<br /> <br /> -- Given an ip, represented as a 4-tuple, and a line expected to come<br /> -- from the ip database, determines whether the ip matches. If it does,<br /> -- the corresponding country is printed, and an exit is signaled.<br /> ipSearch :: (Int, Int, Int, Int) -> B.ByteString -> IO Bool<br /> ipSearch (a,b,c,d) s<br /> | Just (from, to, country) <- parse s,<br /> from <= ip,<br /> ip <= to = B.putStrLn country >> return True<br /> | otherwise = return False<br /> where<br /> ip = d + 256*c + 256*256*b + 256*256*256*a<br /> <br /> parse s = case B.split ',' s of<br /> [f,t,_,_,_,_,c] -> do (from,_) <- B.readInt (B.tail f)<br /> (to, _) <- B.readInt (B.tail t)<br /> return (from, to, B.tail (B.init c))<br /> _ -> Nothing<br /> <br /> main = do (ips:_) <- getArgs<br /> processFile "IpToCountry.csv" (ipSearch $ ipParse ips)<br /> where<br /> ipParse = convert . B.split '.' . B.pack<br /> convert [a,b,c,d] = fromJust $ do (a',_) <- B.readInt a<br /> (b',_) <- B.readInt b<br /> (c',_) <- B.readInt c<br /> (d',_) <- B.readInt d<br /> return (a',b',c',d')<br /> </haskell></div> Dolio