【问题标题】:Kotlin String substitution not working when string is read from file从文件中读取字符串时,Kotlin 字符串替换不起作用
【发布时间】:2018-09-05 07:01:25
【问题描述】:

我编写了一个读取文本文件的代码。文本文件包含我想替换的占位符。替换不能以这种方式工作,并且字符串与占位符一起打印。这是我为此编写的代码:

class TestSub(val sub: Sub) {

    fun create() = template()

    fun template() = Files.newBufferedReader(ClassPathResource(templateId.location).file.toPath()).readText()
}

data class Sub(val name: String, val age: Int)

这是尝试打印最终字符串的主要函数:

fun main(args: Array<String>) {
    val sub = Sub("Prashant", 32)

    println(TestSub(sub).create())
}

但是,当我使用字符串而不是读取文件时,以下代码可以工作(替换 fun template()

fun template() = "<h1>Hello ${sub.name}. Your age is ${sub.age}</h1>"

有没有办法在读取文件内容时使字符串替换起作用?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    Kotlin 不支持来自文件的字符串模板。 IE。像"some variable: $variable" 这样的代码 被编译为"some variable: " + variable。字符串模板在编译时处理,这意味着它不适用于从文件加载的文本,或者如果您执行其他操作以将字符串转义为原始形式。无论哪种方式,正如danielspaniol 所提到的,这将是一个安全威胁。

    剩下三个选项:

    • String.format(str)
    • MessageFormat.format(str)
    • 创建自定义引擎

    我不知道你的文件包含什么,但如果是你在模板函数中使用的字符串,请将其更改为:

    <h1>Hello {0}. Your age is {1,integer}</h1>
    

    这是MessageFormat,这是我个人的喜好。如果您使用String.format,请改用%s,以及其他适当的格式。

    现在,在 MessageFormat.format 中使用它:

    val result = MessageFormat.format(theString, name, age);
    

    请注意,如果您使用MessageFormat,则需要将' 转义为''。见this

    【讨论】:

      【解决方案2】:

      使用${...} 的字符串替换是字符串文字语法的一部分,工作原理大致如下

      val a = 1
      val b = "abc ${a} def"  // gets translated to something like val b = "abc " + a + " def"
      

      因此,当您从文本文件加载时,它无法正常工作。这也将是一个巨大的安全风险,因为它会允许任意代码执行。

      但是我假设 Kotlin 有类似 sprintf 的函数,您可以在字符串中使用 %s 之类的占位符,并且可以将它们替换为值


      看看here。看起来最简单的方法是使用String.format

      【讨论】:

        【解决方案3】:

        字符串模板仅适用于编译时的 Sting 文字,而您从文件中读取的内容是在运行时生成的。

        你需要的是一个模板引擎,它可以在运行时渲染带有变量或模型的模板。

        对于简单的情况,Java 中的String.formatMessageFormat.format 可以工作。

        对于复杂的情况,检查百里香叶,速度等。

        【讨论】:

          【解决方案4】:

          您正在为原始字符串寻找类似于 Kotlin 字符串模板的东西,其中替换了 $var${var} 等占位符按值,但此功能需要在运行时可用(用于从文件中读取的文本)。

          String.format(str)MessageFormat.format(str) 之类的方法使用除了 Kotlin 字符串模板的美元前缀符号之外的其他格式。对于“类似 Kotlin”的占位符替换,您可以使用下面的函数(我出于类似原因开发了该函数)。它支持 $var 或 ${var} 等占位符以及通过 ${'$'}

          转义的美元
          /**
           * Returns a String in which placeholders (e.g. $var or ${var}) are replaced by the specified values.
           * This function can be used for resolving templates at RUNTIME (e.g. for templates read from files).
           *
           * Example: 
            * "\$var1\${var2}".resolve(mapOf("var1" to "VAL1", "var2" to "VAL2")) 
            * returns VAL1VAL2
           */
          fun String.resolve(values: Map<String, String>): String {
          
              val result = StringBuilder()
          
              val matcherSimple = "\\$([a-zA-Z_][a-zA-Z_0-9]*)"           // simple placeholder e.g. $var
              val matcherWithBraces = "\\$\\{([a-zA-Z_][a-zA-Z_0-9]*)}"   // placeholder within braces e.g. ${var}
          
              // match a placeholder (like $var or ${var}) or ${'$'} (escaped dollar)
              val allMatches = Regex("$matcherSimple|$matcherWithBraces|\\\$\\{'(\\\$)'}").findAll(this)
          
              var position = 0
              allMatches.forEach {
                  val range = it.range
                  val placeholder = this.substring(range)
                  val variableName = it.groups.filterNotNull()[1].value
                  val newText =
                      if ("\${'\$'}" == placeholder) "$"
                      else values[variableName] ?: throw IllegalArgumentException("Could not resolve placeholder $placeholder")
                  result.append(this.substring(position, range.start)).append(newText)
                  position = range.last + 1
              }
              result.append(this.substring(position))
              return result.toString()
          }
          

          【讨论】:

            猜你喜欢
            • 2012-10-03
            • 1970-01-01
            • 2021-01-19
            • 2015-06-24
            • 2021-07-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-09-23
            相关资源
            最近更新 更多