Groovy:用同名变量替换字符串中的模板

Groovy:用同名变量替换字符串中的模板,groovy,Groovy,我希望在字符串中查找占位符并将其替换为变量值 字符串可能如下所示: “配置中的URL为{{config.URL}}” 我可以使用任何常规方法查找该值并用另一个字符串替换该值。 使用Eval,我可以部分达到我想要的效果,但还不完全 给定config.url=='www.google.com' 我想把{{config.url}}替换为www.google.com 此外,如果我把字符串改为 “配置中的URL为{{config.url2}}” 它应该从相应的var中读取 这是我试过的一些方法 // Se

我希望在字符串中查找占位符并将其替换为变量值

字符串可能如下所示:

“配置中的URL为{{config.URL}}”

我可以使用任何常规方法查找该值并用另一个字符串替换该值。 使用Eval,我可以部分达到我想要的效果,但还不完全

给定
config.url=='www.google.com'
我想把
{{config.url}}
替换为
www.google.com

此外,如果我把字符串改为
“配置中的URL为{{config.url2}}”
它应该从相应的var中读取

这是我试过的一些方法

// Setup
def description = 'This is my {{ config.good }} description'
def config = [:]
config.good = 'brilliant'
config.bad = 'terrible'

// Verify initial inputs
println "config: $config"
println "description: $description"

// Can I match what I'm looking for? (2 ways)
try1 =  description.replaceAll(/\{\{ (.*) \}\}/, {it[1]})
try2 =  description.replaceAll(/\{\{ (.*) \}\}/, /$1/)
println "try1: $try1"
println "try2: $try2"

// Can I make it look like I expect? (2 ways)
try3 =  description.replaceAll(/\{\{ (.*) \}\}/, {"\${${it[1]}}"})
try4 = description.replaceAll(/\{\{ (.*) \}\}/, /\$\{$1\}/)
println "try3: $try3"
println "try4: $try4"

// This works, but requires that I know the var name ahead of time and pass it in as 'x'
println "tryX1: " + Eval.x(config, 'return "This is my ${x.good} description"')

// Use the String we constructed above... this fails with:
//    groovy.lang.MissingPropertyException: No such property: config for class: Script1
try { println "tryX2: " + Eval.x(this, "return \"$try4\"") }
catch (ex) { println "You suck 1\n" + ex }


// Suspect I need to use Eval.me, but this fails with:
//    groovy.lang.MissingPropertyException: No such property: config for class: Script1
try { println Eval.me('return "This is my ${config.good} description"') }
catch (ex) { println "You suck 2\n" + ex }

//    groovy.lang.MissingMethodException: No signature of method: static groovy.util.Eval.me() is applicable for argument types: (ideaGroovyConsole, org.codehaus.groovy.runtime.GStringImpl) values: [ideaGroovyConsole@7ec508e6, return This is my {{ config.good }} description]
try { println Eval.me("return \"${description}\"") }
catch (ex) { println "You suck 4\n" + ex }

//    groovy.lang.MissingMethodException: No signature of method: Script1.$() is applicable for argument types: (Script1$_run_closure1) values: [Script1$_run_closure1@11b5f4e2]
try { println Eval.x(this, 'return "${description}"') }
catch (ex) { println "You suck 5\n" + ex }

// Neither does this
try { println Eval.me("return ${description}") }
catch (ex) { println "You suck 6\n" + ex }
输出:

config: [good:brilliant, bad:terrible]
description: This is my {{ config.good }} description
try1: This is my config.good description
try2: This is my config.good description
try3: This is my ${config.good} description
try4: This is my ${config.good} description
tryX1: This is my brilliant description
You suck 1
groovy.lang.MissingPropertyException: No such property: config for class: Script1
You suck 2
groovy.lang.MissingPropertyException: No such property: config for class: Script1
This is my {{ config.good }} description
You suck 3
groovy.lang.MissingPropertyException: No such property: description for class: Script1
You suck 4
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script1.groovy: 1: Unexpected input: 'is' @ line 1, column 13.
   return This is my {{ config.good }} description
               ^

1 error

这可能有很多问题,但它可以完成这项工作,而不需要知道变量的名称来传递它们(假设它们存在,可能需要添加一些检查):

产出:

这是我无聊的描述

这是我精彩的描述


这是我糟糕的描述

groovy工具集中最明显的解决此类问题的工具是模板引擎

以下代码:

import groovy.text.SimpleTemplateEngine

def text = 'URL from config is ${config.url}'
def binding = [config: [url: 'www.google.com']]

def template = new SimpleTemplateEngine().createTemplate(text)
def result = template.make(binding).toString()

println result
def config = "foo"
def template = { "URL from config is ${config}" }
println (template())
config = "bar"
println (template())
运行时,打印:

─➤ groovy solution.groovy 
URL from config is www.google.com

─➤
该模板可以与以下不同的绑定一起重复使用:

import groovy.text.SimpleTemplateEngine

def text = 'URL from config is ${config.url}'
def template = new SimpleTemplateEngine().createTemplate(text)

def bindings = [[config: [url: 'www.google.com']],
                [config: [url: 'www.microsoft.com']]]

bindings.each { binding -> 
  println(template.make(binding))
}
def text = 'URL from config is ${config.url}'
config = [url: 'www.google.com']

def template = new SimpleTemplateEngine().createTemplate(text)
def result = template.make(binding.variables.clone()).toString()

println result
其中,我省略了模板上的
toString
调用,因为
println
会为您执行此操作。运行时,此选项将打印:

─➤ groovy solution2.groovy
URL from config is www.google.com
URL from config is www.microsoft.com

─➤
评论后更新

我不完全确定我是否理解这个评论,但我会试一试。如果目标是不必创建单独的变量并将其传递给模板引擎,则可以这样完成:

import groovy.text.SimpleTemplateEngine

def text = 'URL from config is ${config.url}'
def template = new SimpleTemplateEngine().createTemplate(text)

def bindings = [[config: [url: 'www.google.com']],
                [config: [url: 'www.microsoft.com']]]

bindings.each { binding -> 
  println(template.make(binding))
}
def text = 'URL from config is ${config.url}'
config = [url: 'www.google.com']

def template = new SimpleTemplateEngine().createTemplate(text)
def result = template.make(binding.variables.clone()).toString()

println result
这是假设您处于groovy脚本上下文中,而不是groovy类中。Groovy脚本有一个内置的
绑定
变量(类型),它存储您在脚本中声明的任何变量(如
config

我们可以将其用作模板的绑定,以消除创建自定义绑定对象的需要,并使之能够使用脚本碰巧定义的任何现有变量

至于我们为什么要对脚本绑定进行
克隆
,请参见。事实证明,当使用脚本绑定作为模板绑定时,不克隆脚本绑定会破坏groovy脚本的intput/output配置,并基本上一起禁用输出,使其看起来像脚本已退出。这可能被视为groovy中的一个缺陷,因为它非常不直观

替代方法

另一种方法是使用闭包。以下代码:

import groovy.text.SimpleTemplateEngine

def text = 'URL from config is ${config.url}'
def binding = [config: [url: 'www.google.com']]

def template = new SimpleTemplateEngine().createTemplate(text)
def result = template.make(binding).toString()

println result
def config = "foo"
def template = { "URL from config is ${config}" }
println (template())
config = "bar"
println (template())
将打印:

─➤ groovy solution.groovy
URL from config is foo
URL from config is bar

─➤ 

那么
Eval.me('config',config',…${config.url}…')
@daggett试图避免必须在evaluatin端传入变量-只想读取字符串,查找模板,使用其中的任何内容并从相应的变量获取值。如果我必须传入config对象,那么如果我使用另一个变量,它将中断,比如,{{defaults.port}}要使用模板,您必须传递所有变量和将在模板中使用的对象。@daggett-您让我朝着正确的方向出发-最终到达了那里。感谢这是一个比我拼凑的更好的解决方案——不过有一件事。。您仍然需要将config var分配给绑定,这正是我试图避免的(请参见下面我创造性地滥用Eval&evaluate();它只需要temaplate,以及从模板文本本身推断出来的绑定变量。我想这可能像绑定到
这个
?答案更新了,试图解决评论中描述的额外维度。更新很好,感谢您的支持。(我意识到这可能不是完成事情的最佳方式,但它成了一种奇特的方式!)