2012-01-30 29 views
17

Haskellで正規表現を使用して検索と置換を行うための高水準APIはありますか?特に、Text.Regex.TDFAまたはText.Regex.Posixパッケージを探しています。本当に種類の何かのように私は思います:Haskell正規表現ライブラリを使用した置換/置換

f :: Regex -> (ResultInfo -> m String) -> String -> m String 

ので、例えば、同様に、モナドでより高度なものをあなたは

runIdentity . f "dog" (return . const "cat") -- :: String -> String 

を書くことができ、「猫」と「犬」を交換したり、実行します出現数をカウントするなど。

これについては、Haskellのドキュメントはかなり欠けています。いくつかの低レベルのAPIノートはhereです。

答えて

4

私はこの機能を作成し、既存の機能を知りませんが、私はそれをシミュレートするAllMatches [] (MatchOffset, MatchLength) instance of RegexContentのようなものを使用して終了したいと思います:

replaceAll :: RegexLike r String => r -> (String -> String) -> String -> String 
replaceAll re f s = start end 
    where (_, end, start) = foldl' go (0, s, id) $ getAllMatches $ match re s 
     go (ind,read,write) (off,len) = 
      let (skip, start) = splitAt (off - ind) read 
       (matched, remaining) = splitAt len matched 
      in (off + len, remaining, write . (skip++) . (f matched ++)) 

replaceAllM :: (Monad m, RegexLike r String) => r -> (String -> m String) -> String -> m String 
replaceAllM re f s = do 
    let go (ind,read,write) (off,len) = do 
     let (skip, start) = splitAt (off - ind) read 
     let (matched, remaining) = splitAt len matched 
     replacement <- f matched 
     return (off + len, remaining, write . (skip++) . (replacement++)) 
    (_, end, start) <- foldM go (0, s, return) $ getAllMatches $ match re s 
    start end 
28

をどのようにパッケージテキストでsubRegexについて.Regex?

Prelude Text.Regex> :t subRegex 
subRegex :: Regex -> String -> String -> String 

Prelude Text.Regex> subRegex (mkRegex "foo") "foobar" "123" 
"123bar" 
1

多分このアプローチはあなたに合っています。 @のホタルブクロの回答に基づいて

import Data.Array (elems) 
import Text.Regex.TDFA ((=~), MatchArray) 

replaceAll :: String -> String -> String -> String   
replaceAll regex new_str str = 
    let parts = concat $ map elems $ (str =~ regex :: [MatchArray]) 
    in foldl (replace' new_str) str (reverse parts) 

    where 
    replace' :: [a] -> [a] -> (Int, Int) -> [a] 
    replace' new list (shift, l) = 
     let (pre, post) = splitAt shift list 
     in pre ++ new ++ (drop l post) 
3

が、それはただ<<loop>>ないように固定タイプミスと:

replaceAll :: Regex -> (String -> String) -> String -> String 
replaceAll re f s = start end 
    where (_, end, start) = foldl' go (0, s, id) $ getAllMatches $ match re s 
     go (ind,read,write) (off,len) = 
      let (skip, start) = splitAt (off - ind) read 
       (matched, remaining) = splitAt len start 
      in (off + len, remaining, write . (skip++) . (f matched ++)) 
1

あなたはData.Text.ICU.Replace moduleからreplaceAllを使用することができます。

Prelude> :set -XOverloadedStrings 
Prelude> import Data.Text.ICU.Replace 
Prelude Data.Text.ICU.Replace> replaceAll "cat" "dog" "Bailey is a cat, and Max is a cat too." 
"Bailey is a dog, and Max is a dog too."