我试图创建一个简单的Haskell程序,该程序将采用看起来像someFilenameHere0035.xml
的任何行并返回0035
。我的示例输入文件input.txt如下所示:
someFilenameHere0035.xml
anotherFilenameHere4465.xml
并且正在运行:cat input.txt | runhaskell getID.hs
应该返回:
0035
4465
我很难解决这个问题。这就是我到目前为止所拥有的:
import Text.Regex.PCRE
getID :: String -> [String]
getID str = str =~ "([0-9]+)\\.xml" :: [String]
main :: IO ()
main = interact $ unlines . getID
但是我收到一条我根本不理解的错误信息:
• No instance for (RegexContext Regex String [String])
arising from a use of ‘=~’
• In the expression: str =~ "([0-9]+)\\.xml" :: [String]
In an equation for ‘getID’:
getID str = str =~ "([0-9]+)\\.xml" :: [String] (haskell-stack-ghc)
我觉得我真的很亲近,但我不知道从哪里开始。我究竟做错了什么?
答案 0 :(得分:1)
首先,你只需要数字部分,这样我们就可以摆脱\\.xml
。
regex-pcre库为RegexContext Regex String String
而不是RegexContext Regex String [String]
定义了一个实例,因此错误。
因此,如果我们将类型签名更改为String -> String
,则会处理该错误。
unlines
期望[String]这样测试我们此时所拥有的内容我编写了一个快速函数,将其参数包装在一个列表中(这可能是一种更好的方法,但这不是问题的关键所在):
toList :: a -> [a]
toList a = [a]
使用main = interact $ unlines . toList . getID
输出0035运行命令,所以我们几乎就在那里。
getID
传递一个文件内容的字符串,这些字符串由\n
字符方便地分隔。因此,我们可以使用Data.List.Split库中的splitOn "\n"
来获取.xml文件列表。
然后我们只需要在该列表上映射getID
(不再需要toList
)。
这给了我们:
import Text.Regex.PCRE
import Data.List.Split
getID :: String -> String
getID str = str =~ "([0-9]+)"
main :: IO ()
main = interact $ unlines . map getID . splitOn "\n"
当我运行你的命令时,这给了我想要的输出。
希望这有助于:)