我试图匹配正则表达式的所有出现并获得索引作为结果。来自 Real World Haskell 的例子说我能做到
string =~ regex :: [(Int, Int)]
但是,自从RWH发布以来,regex库已经更新,因此打破了这个问题。 (参见All matches of regex in Haskell和"=~" raise "No instance for (RegexContext Regex [Char] [String])")。这样做的正确方法是什么?
更新
我发现matchAll可能会给我我想要的东西。但我不知道如何使用它。
答案 0 :(得分:4)
在创建正则表达式时,使用matchAll
的关键是使用类型注释:: Regex
:
import Text.Regex
import Text.Regex.Base
re = makeRegex "[^aeiou]" :: Regex
test = matchAll re "the quick brown fox"
这将返回一个数组列表。要获取(偏移,长度)对的列表,只需访问每个数组的第一个元素:
import Data.Array ((!))
matches = map (!0) $ matchAll re "the quick brown fox"
-- [(0,1),(1,1),(3,1),(4,1),(7,1),(8,1),(9,1),(10,1),(11,1),(13,1),(14,1),(15,1),(16,1),(18,1)]
要使用=~
运算符,事情可能会因RWH而发生变化。您应该使用预定义类型MatchOffset
和MatchLength
以及特殊类型构造函数AllMatches
:
import Text.Regex.Posix
re = "[^aeiou]"
text = "the quick brown fox"
test1 = text =~ re :: Bool
-- True
test2 = text =~ re :: String
-- "t"
test3 = text =~ re :: (MatchOffset,MatchLength)
-- (0,1)
test4 = text =~ re :: AllMatches [] (MatchOffset, MatchLength)
-- (not showable)
test4' = getAllMatches $ (text =~ re :: AllMatches [] (MatchOffset, MatchLength))
-- [(0,1),(1,1),(3,1),(4,1),(7,1),(8,1),(9,1),(10,1),(11,1),(13,1),(14,1),(15,1),(16,1),(18,1)]
有关可用的上下文的更多详细信息,请参阅Text.Regex.Base.Context的文档。
更新:我认为引入了类型构造函数AllMatches
来解决当正则表达式具有子表达式时引入的歧义 - 例如:
foo = "axx ayy" =~ "a(.)([^a])"
test1 = getAllMatches $ (foo :: AllMatches [] (MatchOffset, MatchLength))
-- [(0,3),(3,3)]
-- returns the locations of "axx" and "ayy" but no subexpression info
test2 = foo :: MatchArray
-- array (0,2) [(0,(0,3)),(1,(1,1)),(2,(2,1))]
-- returns only the match with "axx"
两者基本上都是偏移长度对的列表,但它们意味着不同的东西。