解析 f 风格的内插字符串以恢复参数

Parse an f-style interpolated string to recover arguments

为 f 样式字符串插值创建补码的最佳方法是什么,即在格式化字符串中解析 arguments/numbers 的方法?

例如

val format = "frame%04d.png"
val i = 123
val out = f"frame$i%04d.png"
assert(out == "frame0123.png")

def parse(s: String, pat: String): Int = ???

val j = parse(out, format)
assert(j == 123)

我知道我可以手动构造一个正则表达式,我只是想知道是否有一个通用的方法来处理 f 样式的内插字符串。

我希望得到像这样简单的东西:

val f"frame$j%04d.png" = out

但是

error: macro method f is not a case class, nor does it have an unapply/unapplySeq member

我发现 this nice post 关于使用插值器作为模式匹配器,所以这是你的起点:

object StringMatcher {
  val ZeroFillDec = "%0(\d+)d(.*)".r
  val SimpleDec = "%(\d+)d(.*)".r
  val String = "%s(.*)".r

  def patternize(part: String) = part match {
    case ZeroFillDec(len, rest) => f"(\d{${len.toInt}})$rest"
    case SimpleDec(len, rest) => f"(\d{1,${len.toInt}})$rest"
    case String(rest) => f"(.*)$rest"
    case rest => f"(.*)$rest"
  }
}

implicit class StringMatcher(sc: StringContext) {

  import StringMatcher.patternize

  object pat {
    def unapplySeq(s: String): Option[Seq[String]] = {
      val re = (sc.parts.head ++ (sc.parts.tail map patternize)).mkString.r
      re.unapplySeq(s)
    }
  }
}

使用它,代码

val out = "frame0123_023.png"
val pat"frame$j%04d_$i%03d.png" = out

分配

j: String = 0123
i: String = 023