CLOVER🍀

That was when it all began.

Scala 2.10.0 String Interpolation

今度は、String Interpolationです。
http://docs.scala-lang.org/overviews/core/string-interpolation.html

こちらも、日本語訳が。
http://docs.scala-lang.org/ja/overviews/core/string-interpolation.html

文字列リテラルの前に、補間子というものを入れることでデータから文字列を作成する機構なんだそうで。これは、実例を見た方が早いですね。補間子は、s、f、rawの3つがあります。

例えば、

s"..."

というような書き方になります。

なお、補間子が定義されているのはscala.StringContextになるので、最終的にはここを見るんでしょうね。
http://www.scala-lang.org/api/current/index.html#scala.StringContext

s補間子

動的言語のように、文字列中で変数展開を行います。変数展開を行う時は、$変数名、もしくは${変数名}です。

サンプル。

val stringValue = "Hello World"
val intValue = 1000
val doubleValue = 10.505

println(s"s format example = $stringValue, $intValue, $doubleValue")
println(s"s format example = ${stringValue}, ${intValue}, ${doubleValue}")

実行すると、こうなります。

s format example = Hello World, 1000, 10.505
s format example = Hello World, 1000, 10.505

その他、式を書くことも可能です。

println(s"now = ${new java.util.Date}")

しかも、実行時に解釈しているのではないようなので、こんな風に間違えると

println(s"now = ${new java.util.Dat}")

コンパイルエラーになります。

error: type Dat is not a member of package java.util
    println(s"now = ${new java.util.Dat}")
                                    ^
one error found

すげー。

もちろん、変数展開の場合もその対象の変数がなかったりするとエラーになります。

error: not found: value hoge
    println(s"$hoge")            
               ^
one error found

f補間子

変数展開と、java.util.Formatterで解釈できるフォーマット指定を使える補間子です。

val stringValue = "Hello World"
val intValue = 1000
val doubleValue = 10.505

println(f"f format example = $stringValue%s, $intValue%,3d, $doubleValue%.2f")
println(f"f format example = ${stringValue}%s, ${intValue}%06d, ${doubleValue}%.2f")

実行すると

f format example = Hello World, 1,000, 10.51
f format example = Hello World, 001000, 10.51

となります。

こちらも、s補間子と同様存在しない変数などを展開しようとすると、コンパイルエラーになります。${}中に、式を埋め込むことができる点も同様です。

その他、書式に対して型チェックをしているようで、こんな風に型と書式の指定を間違えると

val doubleValue = 10.505

println(f"$doubleValue%d")

コンパイルエラーになります。

error: type mismatch;
 found   : Double
 required: Int
    println(f"$doubleValue%d")

raw補間子

s補間子とほぼ同じらしいですが、エスケープを実行しないことが異なるそうで。こんなサンプルを実行すると

val stringValue = "Hello World"

println(raw"\r\n\t $stringValue")

\rとか\nとかがそのまま出力されます。

\r\n\t Hello World

どこで使うのか?正規表現とか?

println(raw"\d+".r.findFirstIn("100"))

まあ、この場合はこれでもいいですよね…。

println("""\d+""".r.findFirstIn("100"))

とまあ、こんな感じの使い方をするようです。自分で補間子を定義することもできるようですが、ちょっと省略…。

しかしまあ、こういう書き方してると、どうしてもPythonを連想しますね。

ちょっと気になること

$をエスケープするには?

$$とすればいいみたいです。

val stringValue = "Hello World"

println(s"$stringValue $$stringValue")

結果。

Hello World $stringValue

自分でString Interpolation(補間子)を定義するには?

別エントリを起こしました。こちらを参照してください。

ScalaのString Interpolationを自分で書いて試してみる
http://d.hatena.ne.jp/Kazuhira/20131206/1386345512

また、JPAのJPQLにString Interpolationを適用した例も、書いてみました。

JPQLとString Interpolationを使って遊んでみる
http://d.hatena.ne.jp/Kazuhira/20131214/1387016162

"をエスケープするには?

追記
「"」をエスケープするには、raw string literalと合わせて使えばよいみたいです。

    val str = "quote escaped"
    println(s"""this is \"$str\" s string interpolation""")
    println(f"""this is \"$str\" f string interpolation""")
    println(raw"""this is "$str" raw string interpolation""")

結果。

this is "quote escaped" s string interpolation
this is "quote escaped" f string interpolation
this is "quote escaped" raw string interpolation

raw補間子は、何もしなくていいです。

この後にも書いている
https://issues.scala-lang.org/browse/SI-6476
にすでにこの対処が記載されていたことを、だいぶ後になって知りました。

*ここから先の「"」のエスケープ方法は、以前に書いた内容です
これ、最初にハマりました。

こういうやつを書くと

println(s"this is \"s\" string interpolation")

なんと、文字列リテラルの終わりが分からなくなっているようで、コンパイルエラーになります。

error: ')' expected but string literal found.
    println(s"this is \"s\" string interpolation")

これは、f補間子もraw補間子も同じです。

えー、どうすんの?と思って調べたら、すでに挙がってました。
https://issues.scala-lang.org/browse/SI-6476

こう書け、と。

s"${'"'}"

マジ?${}内に式が埋められることを利用したやり方のようですが…。

ちょっと試してみましょう。

println(s"this is ${'"'}s${'"'} string interpolation")
println(f"this is ${'"'}f${'"'} string interpolation")
println(raw"this is ${'"'}raw${'"'} string interpolation")

実行。

this is "s" string interpolation
this is "f" string interpolation
this is "raw" string interpolation

…動きました。

動いたはいいんですけど、エディタの動きがおかしくなるんですが…。

それか、

s"\042"

と指定すれば動きます。他に方法はないんでしょうか…。

こういう書き方するくらいなら、個人的にはもう変数展開した方が見やすい気がするのですが。

var qq = '"'
println(s"this is ${qq}s${qq} string interpolation")