正则表达式的所有匹配项的索引

8

我正在尝试匹配正则表达式的所有出现,并将索引作为结果。《Real World Haskell》的示例说可以这样做:

string =~ regex :: [(Int, Int)]

然而,由于正则表达式库自RWH出版以来已经更新,因此这种方法已经失效。(请参见Haskell中正则表达式的所有匹配项"=~"引发"No instance for (RegexContext Regex [Char] [String])")。那么正确的方法是什么呢?
更新:
我找到了matchAll,它可能会给我想要的结果。但是我不知道如何使用它。
1个回答

5
使用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以来可能发生了变化。您应该使用预定义类型MatchOffsetMatchLength以及特殊类型构造函数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"

两者都是偏移-长度对的列表,但它们所代表的含义不同。


"typecast :: Regex" 不是类型转换。数据类型没有运行时修改。这是一种类型注释。 - Squidly

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