开发者

"=~" raise "No instance for (RegexContext Regex [Char] [String])"

开发者 https://www.devze.com 2023-04-10 22:13 出处:网络
OS: MacOSX 10.7.1 GHC and Haskell-platform from brew. GHCi, version 7.0.4: http://www.haskell.org/ghc/:? for help

OS: MacOSX 10.7.1 GHC and Haskell-platform from brew.

   GHCi, version 7.0.4: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer-gmp ... linking .开发者_开发百科.. done.
    Loading package base ... linking ... done.
    Loading package ffi-1.0 ... linking ... done.
    Prelude> :m +Text.Regex.Posix
    Prelude Text.Regex.Posix> "foo" =~ "o" :: [String]

    <interactive>:1:7:
        No instance for (RegexContext Regex [Char] [String])
          arising from a use of `=~'
        Possible fix:
          add an instance declaration for
          (RegexContext Regex [Char] [String])
        In the expression: "foo" =~ "o" :: [String]
        In an equation for `it': it = "foo" =~ "o" :: [String]
    Prelude Text.Regex.Posix> "foo" =~ "o" :: String
    Loading package array-0.3.0.2 ... linking ... done.
    Loading package bytestring-0.9.1.10 ... linking ... done.
    Loading package containers-0.4.0.0 ... linking ... done.
    Loading package transformers-0.2.2.0 ... linking ... done.
    Loading package mtl-2.0.1.0 ... linking ... done.
    Loading package regex-base-0.93.2 ... linking ... done.
    Loading package regex-posix-0.95.1 ... linking ... done.
    "o"

I believe libraries updated. And I think the output of "foo" =~ "o" :: [String] is ["o", "o"]

Any suggestion will be appreciate.


ghci> getAllTextMatches ("foo" =~ "o" :: AllTextMatches [] String)
["o", "o"]

I haven't used regexes in Haskell much (which is I think Dan Burton's answer is more idiomatic).

So the way I figured this out is I looked at your type error No instance for (RegexContext Regex [Char] [String]), and popped into ghci:

ghci> :t (=~)
(=~)
  :: (RegexMaker Regex CompOption ExecOption source,
      RegexContext Regex source1 target) =>
     source1 -> source -> target

So RegexContext Regex [Char] [String] is a class that includes the return type of "foo" =~ "o" :: [String]. So I looked to see what instances of this class did exist, so I could find out what the return value was allowed to be:

ghci> :i RegexContext
class RegexLike
        regex source => RegexContext regex source target where
  match :: regex -> source -> target
  matchM :: Monad m => regex -> source -> m target
        -- Defined in Text.Regex.Base.RegexLike
instance RegexContext Regex String String
  -- Defined in Text.Regex.Posix.String
instance RegexLike a b => RegexContext a b [[b]]
  -- Defined in Text.Regex.Base.Context
...
instance RegexLike a b => RegexContext a b (AllTextMatches [] b)
  -- Defined in Text.Regex.Base.Context
...

The AllTextMatches name seemed to indicate what you were looking for, so I checked that out:

ghci> :i AllTextMatches
newtype AllTextMatches f b
  = AllTextMatches {getAllTextMatches :: f b}
        -- Defined in Text.Regex.Base.RegexLike
instance RegexLike a b => RegexContext a b (AllTextMatches [] b)
  -- Defined in Text.Regex.Base.Context

So this was the type to use to extract all the text matches, as I suspected. All I needed to do was indicate that I wanted a return value of that type.

Note also the possible return type of [[b]], which I assume returns a list of lists containing each complete match and all its submatches:

ghci> "foo" =~ "o" :: [[String]]
[["o"],["o"]]
ghci> "foo bar baz" =~ "[aeiou](.)" :: [[String]]
[["oo","o"],["ar","r"],["az","z"]]

So maybe that's the type you meant to use, instead of [String]. I could see [String] as being slightly ambiguous when [[String]] existed - should "foo bar baz" =~ "[aeiou](.)" :: [String] be fst ("foo bar baz" =~ "[aeiou](.)" :: [[String]]) or map fst ("foo bar baz" =~ "[aeiou](.)" :: [[String]]).


This also works

ghci> getAllTextMatches $ "foo" =~ "o" :: [String]
["o","o"]


Try this:

Prelude Text.Regex.Posix> getAllTextMatches ("foo" =~ "o" :: AllTextMatches [] String)
["o","o"]


Another possible solution is:

map head $ "foo" =~ "o" :: [String]

Explanation

Binding the result of (=~) to [[String]] will yield a list of matches, in which each match is represented by list of strings. In each list, its head will be the whole match and it's tail the matches for each submatches:

> "foo goo bar" =~ "(.)o(.)" :: [[String]]
[["foo","f","o"],["goo","g","o"]]

-- Get the second submatch (2) of the first match (0)
> "foo goo bar" =~ "(.)o(.)" !! 0 !! 2 :: String
"o"

-- Get the first submatch (1) of the second match (1)
> "foo goo bar" =~ "(.)o(.)" !! 1 !! 1 :: String
"g"

In short, map head $ string =~ regexp :: [String] contain the whole matches of regexp in string. map tail $ string =~ regexp :: [[String]] contain the sub-matches, indicated in the original regexp by encosing parentheses ().

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号