【问题标题】:Format string in groovy在groovy中格式化字符串
【发布时间】:2018-10-18 08:50:20
【问题描述】:

我想用值替换%s

<server>
    <id>artifactory</id>
    <username>%s</username>
    <password>%s</password>
</server>

groovy 中有myString.format("name", "pass") 方法吗?

【问题讨论】:

  • 将这样的方法添加到StringGroovyMethods实际上可能会很好。

标签: string groovy string-formatting


【解决方案1】:

Groovy 内置了对字符串插值的支持。您只需要使用GString

def name = "name"
def pass = "pass"

String formatted = """
<server>
    <id>artifactory</id>
    <username>$name</username>
    <password>$pass</password>
</server>
"""

如果您的值以数组或集合的形式出现,您甚至可以使用 params[n] 代替命名变量 ($name),如下所示:

def params = ['name', 'pass']

String formatted = """
<server>
    <id>artifactory</id>
    <username>${params[0]}</username>
    <password>${params[1]}</password>
</server>
"""

如果你的字符串需要外化,可以使用template engines

除此之外,你可以使用普通的JavaString.format

def formatted = String.format(myString, "name", "pass")

【讨论】:

  • 这应该是公认的答案。不是因为另一个不起作用,而是groovy不是java,如果你要在groovy中输入Java......那么groovy是干什么用的? (开销?)
  • IMO,这不应该被接受的答案。尽管字符串插值在大多数情况下都可以完成,在字符串格式化完成的情况下,但它不是 100% 替换(特别是方式,它在此处进行了解释)。不同的是,当一个人使用“格式”时,就会有一个模板,它可以用不同的参数多次格式化,而且可能发生在完全不同的地方。相比之下,字符串插值会立即计算(除非使用 ${-&gt; expr} 完成以启用惰性计算),但即使在这种情况下,它的使用方式也略有不同。
  • 关于字符串插值的另一点是(据我所知),它不支持完全格式化(即指定值的格式)。对于当前问题并不重要,但如果要插入的值是例如双打,那么它可能更相关。
  • @DmitriiSemikin 我认为你的评论是关于一个没有被问到的问题。如果问题是关于模板的,那么我会建议groovy's template engines,而仍然不是String.format()。接受的答案始终是 OP 的选择,这就是为什么在许多好的答案中接受一个(或没有)接受的答案是很常见的。从来都不是问题。
  • @ernest_k 同意你的所有观点。我不知道“模板引擎”。从您的链接中,我无法理解,如果它已经是 Groovy 的一部分,还是仅计划包含在内(或者它是外部库?)。除了用于简单用途(例如编写快速而肮脏的脚本)之外,如果您不完全了解模板引擎的工作原理,使用 printf 仍然会更容易:)
【解决方案2】:

基于java的groovy,在java中String类中有一个format方法

https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)

所以这应该可以工作

def s='''<server>
    <id>artifactory</id>
    <username>%s</username>
    <password>%s</password>
</server>'''
println String.format(s, "name", "pass")

【讨论】:

  • 作为另一种变体,您可以使用 String 类作为类别:use(String) { println s.format("name", "pass") }
【解决方案3】:

您可以使用 DefaultGroovyMethods 中的sprintf

def name = "name"
def pass = "pass"

String formatted = """
<server>
    <id>artifactory</id>
    <username>$name</username>
    <password>$pass</password>
</server>
"""
def f = sprintf( formatted, name, pass )

【讨论】:

  • 插值在这里工作,而不是 sprintf。 def f = formatted 将提供完全相同的结果。实际上,如果您这样做def f = sprintf( formatted, "hello", "dude" ),您将不会有任何不同的结果
  • 提及snprintf 在这里是完全有效的,但正如@saamorim 所提到的,这个例子是错误的:它使用字符串插值,这并不能完全回答问题。此外,提供的链接正式有效,并没有真正提供有用的信息。像这样的东西(来自谷歌的第一个结果)更相关:[wjw465150.github.io/blog/Groovy/my_data/Goodness/… 或 [code-maven.com/groovy-printf]。重要的细节是使用标准的 Java 格式化程序 [docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html]
【解决方案4】:

把上面的答案和cmets收集到一个地方,有两种做法:

  1. 基于 Java String.format 功能 see above,它在 groovy 中封装到便利函数 sprintf 中,参见例如herehere
  2. 基于string interpolation,更具体地说是this case
  3. [编辑] 正如 cmets 中的 ernest_k 所建议的,更好的模板解决方案是 template engines。它比裸 String.format 更强大,但当然需要一些学习。

在我个人看来,第一个选项更适合最初提出的问题,因为它允许创建“模板”字符串,然后可以在代码中的任意位置与任意参数一起使用任意次数。这似乎是原始问题中的用例。

一般来说字符串插值和sprintf有两个主要区别:

  1. 字符串插值不允许格式化值。
  2. 字符串插值在其定义的地方(以其正常形式)进行评估,因此它不允许模板化。即使以它的“特殊”形式({-&gt; expr})使用,它仍然没有明确的模板应用行为,而是依赖于外部定义的具有特定名称的变量,我认为这不太可靠。

作为模板用例的说明,请考虑:

// can be defined in the same function, or as static variable in the class or even
// in other class
final String URL_TEMPLATE = 'http://fake.weather.com/rest/%s' // arg - country abbreviation

// ...

// Here we want to get weather for different countries.
def countries = ['US', 'DE', 'GB']
for (country in countries) {
    def url = URL_TEMPLATE.format(country)
    // send the request, accumulate the results
}

这个解决方案使用字符串插值并不容易。当然,我承认,仍然可以基于字符串插值构建解决方案,但看起来会大不相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多