简体   繁体   中英

How to replace more than one element at the same time in a String (Haskell)

i want to take 2 lists for example like this;

find=["Hou","House","Mouse"]
repl=["Mou","Bird","House"]

So when i give a text like that;

"The House with Mouse is big"

Output should be this;

"The Mouse with House is big"

So i wrote this;

replace :: String->String->String->String
replace _ _ []=[]

replace find repl text
  = if take(length find) text == find
      then repl ++ replace find repl (drop (length find) text)
      else [head text] ++ (replace find repl (tail text))

replaceMore ::[String]->[String]->String->String
replaceMore _ _ []=[]
replaceMore _ [] _ =[]
replaceMore [] _ _ =[]
replaceMore find repl text
  = if (tail find) == [] || (tail repl)==[]
      then text
      else replaceMore (tail find)
                       (tail repl)
                       (replace (head find) (head repl) text)

It returns

"The Mouse with Mouse is big"

so it doesn't work like how i want and i think the problem is here;

replaceMore _ _ []=[]
replaceMore _ [] _ =[]
replaceMore [] _ _ =[]

But still i have no idea how to fix this.So any Ideas?

I might give you some ideas towards the working algorithm.

First of all, you need to divide your input String into parts ( [String] ) according to your find strings. So this function is

divideIntoParts :: [String] -> String -> [String]

which works something like

divideIntoParts find "The House with Mouse is big"

gives

["The ", "Hou", "se with ", "Mouse", " is big"]

So it extracts the parts to replace from the string, but preserves the order of letters by keeping other parts in the same list. The naive implementation might look like this

https://gist.github.com/Shekeen/5523749

Next you'll need a function to scan through this list and replace the parts, which need to be replaced. The signature will be

replaceParts :: [String] -> [String] -> [String] -> String

which works like

replaceParts find repl $ divideIntoParts find "The House with Mouse is big"

will be

"The Mouse with House is big"

So your full replace function will look like

replacePatterns :: [String] -> [String] -> String -> String
replacePatterns find repl = (replaceParts find repl) . (divideIntoParts find)

Also you really need to implement a faster substring search algorithm and consider replacing find and repl with one Data.Map

There are two bugs I can see:

  1. The final elements of find and repl are always ignored. replaceMore gives back text when tail find == [] or tail repl == [] ; that should be when find == [] or repl == [] .

    But they should be caught by the earlier equations

     replaceMore _ [] _ =[] replaceMore [] _ _ =[] 

    which, you should be able to see now, are wrong, and should be

     replaceMore _ [] text = text replaceMore [] _ text = text 
  2. But then the output would be

     "The House with House is big" 

    Still wrong. This is because you are building replaceMore out out replace . For each search term, you search through the text, replacing it when found. So you replace "Hou" with "Mou" (so "House" is replaced by "Mouse" ); and then later you replace "Mouse" with "House" (meaning that what was originally "House" ends up as "House" again).

    Instead you should search through the text once, looking for every search term at a position before advancing through the text.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM