2009-06-10 170 views
1

首先,我是斯卡拉新手。斯卡拉 - replaceAllIn

我想在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中查找和替換樣式正則表達式?

+0

對不起 - 什麼是你的問題? – 2009-06-11 00:09:26

回答

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,走的遞歸而不是使用一段時間。而且,當然,stringbuilder會更有效率。在這種情況下,我可能會做到以下幾點:

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") 
    } 

你把追加的非變化部分,其次是下一部分將被替換的方式。

2

util.matching.Regex中有replaceAllIn的風味,它接受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

0

這裏也是有趣的方式如何做同樣的使用功能組成:

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