Haskell中用于正则表达式的“Raw”字符串

6

我似乎在使用Haskell创建正则表达式时遇到了问题,我的目标是将这个字符串(匹配文本中的URL)转换为正则表达式:

\b(((\S+)?)(@|mailto\:|(news|(ht|f)tp(s?))\://)\S+)\b

我想把它转换成正则表达式,但在ghci中一直出现错误。

Prelude Text.RegExp> let a = fromString "\b(((\S+)?)(@|mailto\:|(news|(ht|f)tp(s?))\://)\S+)\b"

<interactive>:1:27:
    lexical error in string/character literal at character 'S'

我猜测它失败的原因是Haskell不理解\S作为转义代码。有没有办法绕过这个问题呢?
在Scala中,你可以用3个双引号括起一个字符串,我想知道在Haskell中是否可以实现类似的功能?
非常感谢您的帮助。

1
根据在https://dev59.com/IFDTa4cB1Zd3GeqPLbfC中找到的答案,Haskell没有原始字符串的语法,因此您必须像@augustss所说的那样转义每个反斜杠。 - João Portela
我相信你必须使用pcre-light或regex-pcre才能获得一个知道\S的实现。除了类似Perl的引擎之外,还有像regex-tdfa这样的类POSIX引擎(不识别\s)。 - Chris Kuklewicz
3个回答

13

在双引号内,你的字符串中每个反斜杠都必须写成双反斜杠。所以:

"\\b(((\\S+)?)(@|mailto\\:|(news|(ht|f)tp(s?))\\://)\\S+)\\b"

更一般的提醒:你最好编写一个适当的解析器而不是使用正则表达式。正则表达式很少能完全做到正确。


... 嗯 - 但是:正则表达式应该更快。为 Type-3 语言编写 LR 或 LL 解析器不应该是一种有效的解决方案。 - phynfo
@phynfo,然而,解析器将允许您可组合地使用模式,并轻松从解析中提取信息。速度并不是一切。 - luqui
如果速度非常重要,我会使用一个简单的正则表达式来识别有效URL的超集,然后再使用真实的解析器来验证这些URL。 - augustss
1
正解加一分,但我很想扣分因为“正则表达式很少能做到完全正确”。正则表达式就像其他编程语言一样——它们只会按照指令执行。不要责怪工具。 - rampion
@rampion 是的,这个表达有点随意,我应该说“复杂的正则表达式很少能完全按照你想象的那样工作。” - augustss
显示剩余4条评论

6

Haskell不支持原生字符串,但是在GHC中使用准引用非常容易实现:

r :: QuasiQuoter
r = QuasiQuoter {      
    quoteExp  = return . LitE . StringL
    ...
}

使用方法:

ghci> :set -XQuasiQuotes
ghci> let s = [r|\b(((\S+)?)(@|mailto\:|(news|(ht|f)tp(s?))\://)\S+)\b|]
ghci> s
"\\b(((\\S+)?)(@|mailto\\:|(news|(ht|f)tp(s?))\\://)\\S+)\\b"

我已经在Hackage发布了一个稍微扩展和记录更多的代码版本,它被称为raw-strings-qq库。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接