2012-09-28 31 views
1

我有一个列表里面有一个字符串,我需要通过Char解构Char,并把它作为Integer放入列表中,但是我受到类型的阻碍有一个字符串列表,但需要一个整数列表

我有什么是我读入单子一个txt文件:

getTxt = do 
    y <- readFile "foo.txt" 
    return y 

foo只包含此:

"1234567890\n" 

然后我想我是密切与序列但让我THI s清单:

["1","2","3","4","5","6","7","8","9","0"] :: [[Char]] 

但我需要[Integer]ord将采取Char -> Int但我怎么读[Char] -> [Int]?在所有这些试验和唯一的错误之后,我不需要最后过滤掉最后一个新行?

有什么建议吗?

+3

这个问题可能会有所帮助:http://stackoverflow.com/questions/2468410/convert-string-to-integer-float-in-haskell – jrajav

回答

1

如果使用ord,该类型匹配,但它不是你想要的,因为ord给你 ASCII值,而不是数值:ord 553,不5。您可以减去 48以获取数字,然后将数字向上滚动到一个数字中,但它会更容易使用库函数。最简单的选择是read

getInt :: IO Integer 
getInt = do 
    y <- readFile "foo.txt" 
    return (read (takeWhile (/='\n') y)) 

正如linked answer, 这里最好的解决方案是使用reads

reads发现可能匹配的列表, 作为对(match,remainingstring), 这是因为它会自动离开换行符剩余的字符串为你工作得很好,

*Main> reads "31324542\n" :: [(Integer,String)]
[(31324542,"\n")]

让我们使用即:

findInt :: String -> Maybe Integer 
findInt xs = case reads xs of    -- have a look at reads xs 
    ((anint,rest):anyothers) -> Just anint -- if there's an int at the front of the list, just return it 
    _ -> Nothing       -- otherwise return nothing 

Maybe是一种方便的数据类型,可以让您在没有崩溃程序或执行异常处理的情况下发生故障。 Just 5意味着你得到了输出,它是5Nothing意味着有问题,没有输出。

addTen :: FilePath -> IO() 
addTen filename = do 
    y <- readFile filename 
    case findInt y of 
     Just i -> putStrLn ("Added 10, got "++show (i+10)) 
     Nothing -> putStrLn ("Didn't find any integer at the beginning of " ++ filename) 

它给你:

*Main> addTen "foo.txt"
Added 10, got 1234567890


如果你只是想字符代表的整数,你可以在你的文件的顶部放import Data.Char

ordzero = ord '0' -- handy constant, 48, to unshift the ascii code to a digit. 

getInts :: FilePath -> IO [Int]   -- ord gives the smaller Int, not Integer 
getInts filename = do 
    y <- readFile filename 
    return [ord achar - ordzero | achar <- takeWhile isDigit y] 

这需要字符串y的人物,只要他们的数字,然后 发现自己ord,减去ord '0'(这是48)把'4'4

0

阅读文档mapfilter。这非常重要。 在你的情况

integersFromFile :: String -> IO [Int] 
integersFromFile filename = map digitToInt <$> readFile filename 
+0

你可能是指'integersFromFile名=地图ORD <$> READFILE filename'因为代码不会检查。 –

+0

是的。你说得对。而且,我没有仔细检查,OP是否需要digitToInt。 – KAction

0

我不明白你在说什么,但我的东西,我认为illusionoflife是在暗示版本列表理解...

do cs <- readFile "foo.txt" 
    return [ord c | c <- cs, c /= '\n'] 

这是有点作弊 - 它假设文件只包含数字和行结束符,并且只是在任何发生的地方剥掉任何行尾字符。

说明 - 这是一个list comprehensionc <- cs基本上依次分配c每个字符。 c /= '\n'过滤出行结束的案例(无论它发生在哪里 - 它不一定非要结尾)。 ord c给出了包含在最终列表中的值。

这可以用filtermap来表示,但是一旦你习惯了它,列表理解就更方便了。

改进后的版本可能会使用isDigit(来自Data.Char)来检查字符。 Maybe还有一种跟踪列表中是否有无效字符的方法,因此您可以稍后检查并报告这些标记,也可以将其过滤掉。

+0

糟糕 - 是的,抱歉,我没有想到,我一直没有使用Haskell。现在应该修复。 – Steve314

+0

感谢您的编辑 – AndrewC

0

所以,你想有一个函数这种类型:

charsToInts :: [Char] -> [Int] 

我们可以通过将问题分解成更小的问题来解决这个问题。首先,我们需要一个转换功能的单CharString

charToString :: Char -> String 
charToString c = [c] 

...那么我们需要转换一个StringInt功能:

stringToInt :: String -> Int 
stringToInt = read 

...那么我们撰写这两个函数来获取转换Char个功能Int S:

charToInt :: Char -> Int 
charToInt = stringToInt . charToString 

无W,我们可以解除该功能通过使用map处理的Char秒的整个列表:

charsToInts :: [Char] -> [Int] 
charsToInts = map charToInt 

...我们就大功告成了!

我为了演示目的采取了非常详细的路径。在我自己的代码,我通常会内联像这样所有这些定义:

charsToInts :: [Char] -> [Int] 
charsToInts = map (read . singleton) 
    where singleton x = [x] 

要在代码中使用stringsToInts,你会这样写:

getTxt :: IO [Int] 
getTxt = fmap charsToInts $ readFile "foo.txt" 

fmap适用charsToIntsreadFile结果,和上面的代码等同于:

getTxt = do 
    chars <- readFile "foo.txt" 
    return $ charsToInts chars 

[外评论:

你甚至可以进一步降低它,与列表理解:

getTxt :: IO [Int] 
getTxt = do 
    chars <- readFile "foo.txt" 
    return [read [d] | d <- chars] 

注意到,虽然类型标注为顶级功能一般都是一个好主意,在这种情况下,它是强制性的(除非你把一个注解进入功能体)。这是因为“阅读”,否则不知道你想要什么类型。 ]

相关问题