2009-06-10 4 views
1

Tout d'abord, je suis nouveau à Scala. J'essaye de faire un analyseur de modèle dans Scala (semblable à Smarty (PHP)). Il doit rechercher dans le document, en remplaçant tout ce qui se trouve dans les balises "{{}}", par tout ce qui est fourni dans HashMap.Scala - replaceAllIn

Je suis actuellement coincé ici:

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) 

est la partie que je l'ai fait remarquer des choses que j'ai pensé à faire.

Merci


Je suis venu un peu plus loin ...

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) 

Au moment juste ajoute actuellement tout ce qui était à l'intérieur de l'étiquette, de retour dans le document. Je me demande s'il y a une façon plus simple de faire une expression rationnelle de style find-and-replace dans Scala?

+0

Je suis désolé - Quelle est votre question? –

+0

Dans le document, il y aura des variables entourées de "{{" et "}}" par ex. "{{ prénom }}". J'ai besoin de trouver le meilleur moyen d'échanger chaque instance de "{{WHATEVER}}" avec une valeur dans le hashmap. –

Répondre

2

Je ferais comme ça (String comme clé au lieu de symbole):

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

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

Si vous préférez ne pas utiliser var, aller récursive au lieu d'utiliser tout. Et, bien sûr, un constructeur de cordes serait plus efficace. Dans ce cas, je pourrais faire ce qui suit:

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

De cette façon, vous gardez la partie non annexant évolution, suivi de la prochaine pièce à remplacer.

2

Il y a une saveur de replaceAllIn dans util.matching.Regex qui accepte un rappel replacer. Un court exemple:

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

Voici comment nous l'utiliser:

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

RemarqueMatcher.quoteReplacement échappe $ caractères dans la chaîne de remplacement. Sinon, vous pouvez obtenir java.lang.IllegalArgumentException: Illegal group reference, replaceAll and dollar signs. Voir the blog post sur pourquoi cela peut arriver.

0

Voici également de manière intéressante la façon de faire les mêmes fonctions à l'aide composent:

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