2012-01-30 9 views
17

Czy istnieje interfejs API wysokiego poziomu do robienia wyszukiwania i zamiany za pomocą wyrażeń regularnych w Haskell? W szczególności patrzę na pakiety Text.Regex.TDFA lub Text.Regex.Posix. Naprawdę chciałbym coś typu:zamiennik/podstacja z bibliotekami Haskella regexa

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

tak, na przykład, aby zastąpić „pies” z „kotem” można napisać

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

czy bardziej zaawansowanych rzeczy z monady, jak liczenie wystąpień, itp.

Dokumentacja Haskell jest dość brakuje. Niektóre notatki API niskiego poziomu to here.

Odpowiedz

4

nie wiem o wszelkich istniejących funkcji, która tworzy tę funkcjonalność, ale myślę, że będę skończyć używając coś jak AllMatches [] (MatchOffset, MatchLength) instance of RegexContent to zasymulować:

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

Jak o subRegex w opakowaniu Tekst .Regex?

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

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

Może to podejście pasuje do Ciebie.

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

podstawie odpowiedzi @ zerwa, ale z typo stałej więc nie tylko <<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

Można użyć replaceAll z Data.Text.ICU.Replace module.

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."