【问题标题】:Haskell string replaceHaskell 字符串替换
【发布时间】:2016-03-20 23:21:10
【问题描述】:

如何用字符串中的多个字符替换一个字符。 我可以用下面的另一个字符替换一个字符:

  replaceO [] = []
  replaceO (x:xs) =
     if x == '('
     then '\n' : replaceO xs
     else x : replaceO xs

但我想用“\n\t\t”替换'(',而不仅仅是'\n'。

--------- 更新 -------------- 根据下面的答案,我可以把它变成一个接受字符串并返回这样的字符串的函数:

ReplaceFun str :: String -> String
ReplaceFun str = do
    concatMap (\str -> if str == '.' then "foo" else [str])

这不起作用,有人可以指出我的错误吗?我对 Haskell 很陌生。

这是嵌套缩进的内容:

replaceO (x:xs) n l =
    if x == '('
    then "\n" ++ (showTabs n "-") ++ replaceO xs (n + 1) 'l'
    else
        if x == ')'
        then "\n" ++ (showTabs n "-") ++ replaceO xs (n - 1) 'l'
        else x : replaceO xs n 'l'

【问题讨论】:

  • 你没有给concatMap足够的参数-replaceFun的右轴(也注意小写)应该是String类型,但concatMap (\str -> if str == '.' then "foo" else [str])的类型是String -> String。你可能想要replaceFun = concatMap (\str -> if str == '.' then "foo" else [str])

标签: string haskell replace


【解决方案1】:

只需使用concatMap

Prelude> concatMap (\x -> if x == '.' then "foo" else [x]) "example..."
"examplefoofoofoo"

【讨论】:

  • 你能把它定义为一个函数吗?我无法让它工作。
  • 我这样做了,但不起作用:replaceFun w :: String -> String replaceFun w = do concatMap (\x -> if x == '.' then "foo" else [x])
  • 你能看一下问题的更新部分吗?
  • @2D3D4D f = concatMap (\x -> if x == '.' then "foo" else [x]) 或更一般的f a b s = concatMap (\x -> if x == a then b else [x]) s
【解决方案2】:

扩展你的例子,你可以用 "\n\t\t" 代替 "(" 只需在递归调用的结果前面加上多个东西

replace1 [] = []
replace1 (x:xs) =
   if x == '('
   then '\n' : '\t' : '\t' : replace1 xs
   else x : replace1 xs

当然,这相当于使用"\n\t\t" ++

replace2 [] = []
replace2 (x:xs) =
   if x == '('
   then "\n\t\t" ++ replace2 xs
   else x : replace2 xs

如果我们注意到x : 等价于[x] ++

replace3 [] = []
replace3 (x:xs) =
   if x == '('
   then "\n\t\t" ++ replace3 xs
   else [x] ++ replace3 xs

然后我们可以分解出重复的递归调用

replace4 [] = []
replace4 (x:xs) = (if x == '(' then "\n\t\t" else [x]) ++ replace4 xs

那么为了清楚起见,我们可以将if 语句过滤成一个函数:

replace5 [] = []
replace5 (x:xs) = f x ++ replace5 xs
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

然后我们可以重新组织我们的代码 - 而不是交替地将 f 应用于每个 x 和 将它附加到我们的结果中,我们可以将f 应用于所有xs,然后连接所有结果:

replace6 xs = concat $ map f xs
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

但是concat $ map f xs 被频繁使用以至于它有了另一个名字:

replace7 xs = concatMap f xs
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

其实它还有一个,因为[]是一个monad:

replace8 xs = xs >>= f
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

但如果我们这样做,我们还不如完全使用 Monad:

replace9 xs = do
  x <- xs
  if x == '(' 
     then "\n\t\t" 
     else [x]

但我个人可能只会停在replace7

【讨论】:

  • 谢谢@rampion,刚刚意识到一些事情,我想用它来漂亮地打印一棵树。但是所有节点都会以相同的缩进结束。我想增加每个嵌套节点的缩进。这很容易吗?
  • 当然!查看早期版本之一。如果replace2 采用另一个参数n,在用换行符替换“(”后要插入多少个制表符呢?现在递归调用需要两个参数 - 字符串的其余部分和制表符的数量。什么如果 (a) x 不是括号,(b) 它是一个开括号,或者 (c) 它是一个闭括号,你会进行递归调用吗?
  • 如果不是括号,则不需要替换。如果是左括号,那么我们替换\n 和\t(对于每一级嵌套)。我认为右括号可以替换为空字符串。
  • 告诉我你对我上面的问题的了解程度!您是否定义了一个新的 replace 函数,它接受两个参数 xsn
  • 2D3D4D:好的开始!现在考虑你想要 "a(a(a(a("" 的样子,并使用它作为输入来遍历你的实现。看看你是否得到你想要的。看看哪里出了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-07
  • 1970-01-01
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
相关资源
最近更新 更多