如何在Haskell中使用此正则表达式?

时间:2017-09-16 23:46:39

标签: regex haskell

我试图创建一个简单的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)

我觉得我真的很亲近,但我不知道从哪里开始。我究竟做错了什么?

1 个答案:

答案 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"

当我运行你的命令时,这给了我想要的输出。

希望这有助于:)