【问题标题】:recursive function for handling Data.Text replace outputs a way longer text than expected用于处理 Data.Text 的递归函数替换输出比预期更长的文本
【发布时间】:2013-02-15 15:30:03
【问题描述】:

我在 Haskell 中有一个handleReplace 函数,它的类型是

handleReplace :: Character -> T.Text -> T.Text

T 只是作为合格导入的 Data.Text 模块 所以这个函数接受一个字符类型,它的定义如下:

data Character  = Character (String, String, String, String) [(String,String)] Case String Stringderiving (Read, Show)

和一个文本值。 它只关心字符串元组的列表,并尝试用 Data.Text 字符串中元组中的第二项替换元组中第一项的每次出现,以及该元组列表中的每个元素。一个例外是,如果要替换的匹配项位于以/ 开头的单词内。我这样定义函数:

handleReplace :: Character -> T.Text -> T.Text
handleReplace (Character _ []   _ _ _)        s = s
handleReplace (Character _ ((a, b):xs) _ _ _) s = handleReplace emptyCharacter string
                                                where emptyCharacter = Character ([], [], [], []) xs Normal [] []
                                                      string         = T.unwords $ map (\ x 
                                                                                         -> if (T.head x) == '/'
                                                                                                then x
                                                                                                else T.replace (T.pack a) (T.pack b) s
                                                                                      ) $ T.words s

不幸的是,它不起作用。它不会抛出任何错误,但我没有得到预期的输出。 运行时

handleReplace (Character ([],[],[],[]) [("u","U"),("v","wv")] Normal [] []) $ T.pack "/uu v uu vvuu"

我希望它返回 "/uu wv UU wvwvUU"(显然是 Text 类型)但是当我在 ghci 中尝试时,我得到:

"/uu /UU /uu /UU wv UU wvwvUU /UU wv UU wvwvUU /UU wv UU wvwvUU ...

等等。 为什么?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    在不同的范围内有很多单字母变量可以很容易地制作 这种错误。我怀疑你想要的是

    else T.replace (T.pack a) (T.pack b) x
    

    而不是

    else T.replace (T.pack a) (T.pack b) s
    

    否则,您将多次对整个字符串执行替换, 而不是特定的块。此更改似乎提供了所需的输出 至少你的测试用例。

    顺便说一句,这就是我写它的方式。不完全指向 免费,但更接近,更容易理解。

    import Control.Arrow ((***))
    import qualified Data.Text as T
    
    handleReplace :: Character -> T.Text -> T.Text
    handleReplace (Character _ [] _ _ _) = id
    handleReplace (Character _ xs _ _ _) = doReplacements $ map (T.pack *** T.pack) xs
    
    doReplacements :: [(T.Text, T.Text)] -> T.Text -> T.Text
    doReplacements reps = T.unwords . map replaceAll . T.words
        where replaceAll word = foldl replaceSingle word reps
    
    replaceSingle :: T.Text -> (T.Text, T.Text) -> T.Text
    replaceSingle word (inp, out)
        | T.head word == '/' = word
        | otherwise          = T.replace inp out word
    

    【讨论】:

    • ...避免单字母变量的最佳方法是完全避免变量。 s 是不必要的,handleReplace 可以很好地写成带有无点替换器的折叠。
    • 非常感谢!就是这样。 @leftaroundabout,我该怎么做?
    • @nils8950 我不能让它完全免费,但我添加了一个如何清理它的示例。我认为您无需担心使其无点,只需将其模块化即可。
    猜你喜欢
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 2021-03-20
    • 2019-08-28
    • 2016-10-05
    • 2015-03-10
    • 2022-06-18
    • 1970-01-01
    相关资源
    最近更新 更多