Haskell字符串字符替换求助:无库实现特定字符替换需求
Hey there! Let's break down why your code isn't working and fix it properly. I'll walk through the issues and give you both a corrected version and a more elegant optimized solution.
First, the Problems in Your Code
Syntax Error in the
letBlock
You've jammed all yourreplpatterns together on one line, which Haskell doesn't accept. Multiple function clauses in alet(orwhere) block need to be separated by newlines (or semicolons, but newlines are cleaner).Non-Exhaustive Pattern Matching
Yourreplfunction only handles'/'and digits 2-9. It completely ignores'1'and other characters like the'w'in your example. When Haskell hits an unrecognized character, it'll throw a runtime error for non-exhaustive patterns.Using
mapInstead ofconcatMap
Yourreplfunction returns aString(a list of chars), butmap repl xwill give you a list of strings ([String]), not a single merged string. You need to concatenate those results into one final string.
Fixed Version (Direct Correction)
Here's your code adjusted to fix all the above issues:
replace :: String -> String replace x = let repl '/' = replicate 10 '1' -- Use replicate to avoid typing 10 '1's manually repl '9' = replicate 9 '1' repl '8' = replicate 8 '1' repl '7' = replicate 7 '1' repl '6' = replicate 6 '1' repl '5' = replicate 5 '1' repl '4' = replicate 4 '1' repl '3' = replicate 3 '1' repl '2' = replicate 2 '1' repl '1' = "1" -- Keep '1' as-is repl c = [c] -- Preserve any other character (like 'w') in concatMap repl x -- concatMap merges all the returned strings into one
Optimized Version (Cleaner, Less Repetition)
Instead of writing a separate clause for every digit, we can convert the character to its numeric value and generate the right number of '1's automatically. This avoids repetitive code:
replace :: String -> String replace = concatMap repl where repl '/' = replicate 10 '1' repl c | c `elem` ['2'..'9'] = replicate (read [c] :: Int) '1' | otherwise = [c] -- Handles '1' and all non-target characters
How This Works
concatMapappliesreplto each character in the input string, then concatenates all the resulting small strings into one final output.replicate n '1'creates a string ofncopies of '1'—way cleaner than typing out multiple '1's manually.- The guard clause checks if the character is a digit from 2-9, converts it to an integer with
read [c], then uses that number to generate the correct number of '1's. - The
otherwisecase ensures every other character (including '1' and 'w') is kept exactly as it is.
Testing this with your example string "w1w1w8/w7w1w1//w" will give you the expected result: "w1w1w11111111/w1111111w1w1/1111111111/w" (with 8 '1's for '8', 10 '1's for each '/', 7 '1's for '7', etc.).
内容的提问来源于stack exchange,提问作者Marco Michaelis

