Haskell在一次传递中用正则表达式替换多个子串

时间:2018-02-01 20:48:00

标签: regex haskell

假设我有一个字符串s和一个字符串ts的元组列表,其中元组中的第一个元素是s的子字符串我想要替换与相应的第二个元素。在我的例子中,字符串s将始终是以空格分隔的不同单词列表;此外,我希望将s中的每个单词全部替换为ts中的相应值(我希望我的意图在此处清楚)。第一次尝试可能是:

import qualified Text.Regex as R -- from regex-compat    

replaceAllIn :: String -> [(String, String)] -> String
replaceAllIn = foldl (\acc, (k, v) -> R.subRegex (R.makeRegex k) acc v)

当一个键是另一个键的子串时,这当然不起作用

λ> s = "blah blahblee"
λ> ts = [("blah", "asdf"), ("blahblee", ";lkj")]
λ> replaceAllIn s ts
"asdf asdfblee"

因为第一个键替换了" blah"在第一次通过时,留下一条不再有任何匹配的字符串" blahblee"第二次传球

有没有办法在一次通过字符串时实现我想要的东西?或者是否有一种内置方式(在某些库中某处)可以一次替换多个模式?

编辑:发布后我立即意识到我不知道为什么我在这里使用正则表达式。但是如果我用MissingH的Data.String.Utils中的replace替换正则表达式替换,问题仍然有效。

2 个答案:

答案 0 :(得分:2)

扩展我之前的评论,您可以先处理要替换的最长字符串:

# query the table and select id, derivable_type and derivable_id
my_table_ids = MyTable
  .group("derivable_type, derivable_id")
  .select("MAX(id) AS my_table_id, derivable_type, derivable_id")

# use subquery to allow rails to use ORDER BY in find_each 
MyTable
  .where(id: my_table_ids.select('my_table_id'))
  .find_each { |row| do_something(row) } 

答案 1 :(得分:1)

  

就我而言,字符串s将始终是以空格分隔的不同单词列表;此外,我希望完整地替换s中的每个单词

我看到的第一步是将字符串拆分(或分隔)为空格。

接下来,正如@keuhlen建议的那样,我将替换对从最长到最短排序。

之后,问题应该很简单,并且子串搜索速度很快,因为它会通过字边界前进。

(一个额外的优化可能是按照长度对搜索模式进行分组,例如在树或数组中,这样对于较短的输入单词,从不考虑更长的模式。)