Scala - replaceAllIn

时间:2009-06-10 23:48:44

标签: regex scala

首先,我是Scala的新手。

我正在尝试在Scala中创建模板解析器(类似于Smarty(PHP))。它需要搜索文档,用“HashMap”中提​​供的任何内容替换“{{}}”标记内的任何内容。

我目前被困在这里:

import scala.collection.mutable.HashMap
import scala.io.Source

class Template(filename: String, vars: HashMap[Symbol, Any]) {
  def parse() = { 
    var contents = Source.fromFile(filename, "ASCII").mkString
    var rule = """\{\{(.*)\}\}""".r

    //for(rule(v) <- rule findAllIn contents) {
    //  yield v
    //}

    //rule.replaceAllIn(contents, )
  }
}

var t = new Template("FILENAME", new HashMap[Symbol, Any])
println(t.parse)

我评论过的部分是我考虑过的事情。

由于


我再来一点......

import scala.collection.mutable.HashMap
import scala.io.Source
import java.util.regex.Pattern
import java.util.regex.Matcher

class Template(filename: String, vars: HashMap[Symbol, Any]) {

  def findAndReplace(m: Matcher)(callback: String => String):String = {
    val sb = new StringBuffer
    while (m.find) { 
      m.appendReplacement(sb, callback(m.group(1))) 
    }
    m.appendTail(sb)
    sb.toString
  }

  def parse() = { 
    var contents = Source.fromFile(filename, "ASCII").mkString
    val m = Pattern.compile("""\{\{(.*)\}\}""").matcher(contents)

    findAndReplace(m){ x => x }

  }
}

var t = new Template("FILENAME.html", new HashMap[Symbol, Any])
println(t.parse)

目前它只是添加标签内的任何内容,然后返回到文档中。我想知道在Scala中是否有更简单的方法来执行查找和替换样式regexp?

3 个答案:

答案 0 :(得分:2)

我会这样做(String作为键而不是符号):

var s : String = input // line, whatever
val regexp = """pattern""".r

while(regexp findFirstIn s != None) {
  s = regexp replaceFirstIn (s, vars(regexp.findFirstIn(s).get))
}

如果您不想使用var,请使用递归而不是使用while。当然,字符串构建器会更有效率。在这种情况下,我可能会做以下事情:

val regexp = """^(.*?)(?:{{(pattern)}})?""".r
for(subs <- regexp findAllIn s)
  subs match {
    case regexp(prefix, var) => sb.append(prefix); if (var != null) sb.append("{{"+vars(var)+"}}")
    case _ => error("Shouldn't happen")
  }

这样你就可以继续追加不变的部分,接着是要替换的下一部分。

答案 1 :(得分:2)

replaceAllIn中有一种util.matching.Regex可以接受replacer回调。一个简短的例子:

import util.matching.Regex
def replaceVars(r: Regex)(getVar: String => String) = {
  def replacement(m: Regex.Match) = {
    import java.util.regex.Matcher
    require(m.groupCount == 1)
    Matcher.quoteReplacement( getVar(m group 1) )
  }
  (s: String) => r.replaceAllIn(s, replacement _)
}

我们将如何使用它:

val r = """\{\{([^{}]+)\}\}""".r
val m = Map("FILENAME" -> "aaa.txt",
            "ENCODING" -> "UTF-8")
val template = replaceVars(r)( m.withDefaultValue("UNKNOWN") )

println( template("""whatever input contains {{FILENAME}} and
unknown key {{NOVAL}} and {{FILENAME}} again,
and {{ENCODING}}""") )

  

注意 Matcher.quoteReplacement在替换字符串中转义$个字符。否则你可能会得到java.lang.IllegalArgumentException: Illegal group reference, replaceAll and dollar signs。有关可能发生这种情况的原因,请参阅the blog post

答案 2 :(得分:0)

以下是使用函数compose进行相同操作的有趣方法:

  val Regexp = """\{\{([^{}]+)\}\}""".r

  val map = Map("VARIABLE1" -> "VALUE1", "VARIABLE2" -> "VALUE2", "VARIABLE3" -> "VALUE3")

  val incomingData = "I'm {{VARIABLE1}}. I'm {{VARIABLE2}}. And I'm {{VARIABLE3}}. And also {{VARIABLE1}}"


  def replace(incoming: String) = {
    def replace(what: String, `with`: String)(where: String) = where.replace(what, `with`)
    val composedReplace = Regexp.findAllMatchIn(incoming).map { m => replace(m.matched, map(m.group(1)))(_) }.reduceLeftOption((lf, rf) => lf compose rf).getOrElse(identity[String](_))
    composedReplace(incomingData)
  }

  println(replace(incomingData))

  //OUTPUT: I'm VALUE1. I'm VALUE2. And I'm VALUE3. And also VALUE1