我在Haskell中有一个handleReplace
函数,其类型为
handleReplace :: Character -> T.Text -> T.Text
T只是Data.Text模块作为限定导入 所以这个函数采用了一个Character类型,它的定义如下:
data Character = Character (String, String, String, String) [(String,String)] Case String Stringderiving (Read, Show)
和Text值。
它只关心String元组的列表,并尝试将元组中第一个项的每个匹配项替换为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 ...
等。 为什么呢?
答案 0 :(得分:3)
在不同的范围内拥有大量单字母变量使其易于制作 这种错误。我怀疑你想拥有的是
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