如何使用任何与正则表达式相关的Haskell库从123 :: Integer
这样的字符串中检索123_
值?
import Text.Regex.Posix
let (_,_,_,[sectionKey]) = ("123_") =~ ("(\\d+)_" :: String) :: (String, String, String, [Int])
我已尝试过上述(使用https://hackage.haskell.org/package/regex-posix库)产生错误:
• No instance for (RegexContext
Regex [Char] (String, String, String, [Int]))
arising from a use of ‘=~’
• In the expression:
("123_") =~ ("(\\d+)_" :: String) ::
(String, String, String, [Int])
In a pattern binding:
(_, _, _, [sectionKey])
= ("123_") =~ ("(\\d+)_" :: String) ::
(String, String, String, [Int])
这是一个简化的案例,我正在寻找一种能够提供正则表达式兼容解决方案的解决方案。
答案 0 :(得分:7)
首先,我不会使用正则表达式库 - 因为now you got two problems,haskell有一个很好的 - 没有伟大的解析器生态系统可以为你完成这项工作。
你的问题的解决方案是 - 我认为你使用了错误的正则表达式。
$ stack ghci --package regex-posix --package safe
...
Prelude> :m + Safe Text.Regex.Posix
Prelude Safe Text.Regex.Posix> readMay ("123_" =~ "[0-9]+") :: Maybe Integer
Just 123
使用正则表达式的缺点是它们首先难以理解/正确,并且在事后保持,容易出错(在我看来) - 而且。当您与之匹配时,您将获得匹配的String
。即("123_" =~ "([0-9]+)_") :: String
将产生“123_”而非“123”,因此“readMay ...”将返回Nothing
而不是Just 123
。
因此我建议使用解析库 - 类似attoparsec。但正如我所说,如果你不喜欢这个,你会有很多解析选择。
$ stack ghci --package attoparsec
Prelude> :set -XOverloadedStrings
Prelude> import Data.Attoparsec.ByteString.Char8 as C8
Prelude Data.Attoparsec.Char8> :{
Prelude Data.Attoparsec.Char8| strangeNumber = do
Prelude Data.Attoparsec.Char8| d <- decimal
Prelude Data.Attoparsec.Char8| char '_'
Prelude Data.Attoparsec.Char8| return d
Prelude Data.Attoparsec.Char8| :}
Prelude C8> parseOnly strangeNumber "123_" :: Either String Integer
Right 123
将它放在ghci中有点笨拙,但在文件中它非常精细且可维护 - 所以如果你想在数字的开头和/或结尾允许可选的'_',你可以把它写成< / p>
StrangeNumber.hs
strangeNumber :: Parser Integer
strangeNumber = do
skipMany (char '_')
d <- decimal
skipMany (char '_')
return d
并在GHCi中使用它
Prelude Data.Attoparsec.ByteString.Char8> parseOnly strangeNumber "123_"
Right 123
Prelude Data.Attoparsec.ByteString.Char8> parseOnly strangeNumber "_123_"
Right 123
Prelude Data.Attoparsec.ByteString.Char8> parseOnly strangeNumber "_123__"
Right 123