2012-01-30 29 views
17

Có API cấp cao để thực hiện tìm kiếm và thay thế bằng regex trong Haskell không? Đặc biệt, tôi đang xem các gói Text.Regex.TDFA hoặc Text.Regex.Posix. Tôi muốn thực sự thích một cái gì đó kiểu:thay thế/trạm biến đổi với thư viện regex Haskell

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

như vậy, ví dụ, để thay thế "chó" với "mèo" bạn có thể viết

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

hoặc làm những việc cao cấp hơn với các đơn nguyên, như đếm số lần xuất hiện, v.v.

Tài liệu Haskell cho điều này khá thiếu. Một số ghi chú API cấp thấp là here.

Trả lời

4

Tôi không biết về bất kỳ chức năng hiện có tạo ra chức năng này, nhưng tôi nghĩ rằng tôi muốn kết thúc bằng một cái gì đó giống như AllMatches [] (MatchOffset, MatchLength) instance of RegexContent để mô phỏng nó:

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

Làm thế nào về subRegex trong gói bản .Regex?

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

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

có thể phương pháp này phù hợp với bạn.

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

Dựa trên câu trả lời @ rampion, nhưng với typo cố định do đó nó không chỉ <<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

Bạn có thể sử dụng replaceAll từ 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." 
Các vấn đề liên quan