Haskell seems to be missing a String replace function. Text.Regex.subRegex seemed like overkill. So I wrote one. It actually works on any list, not just Strings.
replace :: Eq a => [a] -> [a] -> [a] -> [a] replace  _ _ =  replace s find repl = if take (length find) s == find then repl ++ (replace (drop (length find) s) find repl) else [head s] ++ (replace (tail s) find repl)
*Main> replace "hello" "h" "" "ello" *Main> replace "hello" "l" "" "heo" *Main> replace "hello" "x" "" "hello" *Main> replace "100,000,000" "," "hello" "100hello000hello000" *Main> replace "100,000,000" "," "" "100000000" *Main> replace [1,2,3]   [9,2,3] *Main> replace [4,5,6,1,2,3,7,8,9,2,3,6,5,4,1,2,3] [1,2,3]  [4,5,6,10,7,8,9,2,3,6,5,4,10]
If this function is already in the standard libraries somewhere or if this can be improved in some way please leave a comment to let me know. Thanks!
11 Replies to “Replace in Haskell”
“head” and “tail” should be used sparingly, because “head” is a partially defined function (see “head ”).
sorry, too smart (sic!) for my own good. my “isPrefixOf” is broken, instead use “Data.List.isPrefixOf”
Thanks jethr0. I see you’ve moved the list to act on to the last of the arguments. Someone else on #haskell suggested that too, to improve composability.
Yeah, the general rule is to always order parameters to functions in order of increasing likelihood of variation. In this case, for instance, it seems more likely that the same substitutions will be used on many different lists, rather than many different substitutions on the same initial list.
The first function here is missing a check that can cause infinite recursion if an empty `find` list is given
it needs something like…
The second function given only replaces the first instance of the string, and if the `find` list is empty then it is equivalent to
the fourth line could be changed to…
but then it has the same problem as the first function, and needs another check
I chose to write my replace as follows
I decided that an empty match list would mean inserting the new element between all of the elements in the list, but maybe the new element should be inserted on the beginning of the list as well.
another function that works nicely with replace
replace “abc” “a” “b” –> “bb”. I don’t think that’s what you want, is it? There’s a solution over here: http://groups.google.com/group/fa.haskell/browse_thread/thread/daa11e5471402149?pli=1 replace :: (Eq a) => [a] -> [a] -> [a] -> [a] replace _ _  =  replace old new xs@(y:ys) = case stripPrefix old xs of Nothing -> y : replace old new ys Just ys’ -> new ++ replace old new ys’ Notice that the haystack argument is the last argument, instead of the first. This is so that you can do function composition nicely, for example: quote = replace “” “>” . replace “&” “&” If the haystack argument were first instead of last, the definition of quote would get a lot messier.
Oh the irony… your comment code doesn’t escape my comment correctly! Trying this again: quote = replace “<” “<” . replace “>” “>” . replace “&” “&”
Hi, you may use replace from Data.String.Utils
Data.String.Utils is GPL licensed; not desirable for a lot of people.
@Doug: Only for delusional criminals, who think one could „own“ and „sell“ information. Reality doesn’t care about them, and we should neither.
`isPrefixOf find s` should perform better than `take (length find) s == find` as it only needs to traverse `find` once. (`isPrefixOf` is found in `Data.List`)