QuoteとUnquote #golang
October 19, 2019
Quoteを行う
Goで文字列を""
で括って(Quoteして)表示したい場合、fmt.Printf
関数を用いて行うことが多いでしょう。
package main
import "fmt"
func main() {
fmt.Printf(`"%s"`, "hoge")
}
これを実行すると以下のようになります。
$ go run main.go
"hoge"
文字列中に"
が含まれていた場合に、Goのソースコード上の文字列のようにエスケープする場合には%q
が便利でしょう。
package main
import "fmt"
func main() {
fmt.Printf("%[1]s %[1]q\n", "hoge")
fmt.Printf("%[1]s %[1]q\n", `"fuga"`)
}
これを実行すると以下のようになります。
$ go run main.go
hoge "hoge"
"fuga" "\"fuga\""
なお、%[1]s
や%[1]q
の[1]
は書式を適用する引数のインデックスを指します。この場合は、"hoge"
や`"fuga"`
にあたります。インデックスを指定することで同じ引数に複数回別の書式を指定することが可能になります。
なお、単純に文字列をQuoteしたい場合はfmt.Sprintf
関数を使って同様に行うこともできますが、以下のようにstrconv.Quote
関数を用いた方がよいでしょう。
package main
import (
"fmt"
"strconv"
)
func main() {
s1 := "hoge"
s2 := strconv.Quote(s1)
fmt.Println(s1, s2)
}
このコードを実行すると以下のようになります。
$ go run main.go
hoge "hoge"
Unquoteを行う
Quoteの逆を(Unquote)を行いたい場合に、strings.Trim
関数を使ってstrings.Trim(str, `"`)
のようにしてしまいがちですが、これでは十分にUnquoteされません。Goの文字列には`hoge`
のようなものも許容されるからです。
strings.Trim
関数の代わりに以下のようにstrconv.Unquote
関数を用いることで簡単にUnquoteを行うことができます。
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
s1 := `"hoge"`
s2, err := strconv.Unquote(s1)
if err != nil {
// エラー処理
fmt.Fprintln(os.Stderr, "Error:", err)
os.Exit(1)
}
fmt.Println(s1, s2)
}
このコードを実行すると以下のように表示されます。
$ go run main.go
"hoge" hoge
hoge
や"fuga
のようにQuoteされていない文字列が引数として渡されるため、strconv.Unquote
関数は第2戻り値にエラーを返します。そのため、適切にエラー処理を行いましょう。
Unquoteと静的解析
Unquoteを行う機会はあまりなさそうですが、静的解析を行う際に非常に便利です。
静的解析で用いられるGoのプログラムを木構造で表した抽象構文木にはast.BasicLit
型で表現されるノードがあります。ast.BasicLit
型は数値リテラル(123
や10.5
など)や文字列リテラル("hoge"
や`fuga`
など)を表す構造体です。
Value
フィールドにそのリテラルの値がソースコード上の表記で文字列として保持されています。たとえば、123
のような数値リテラルは"123"
のような文字列で、文字列リテラルは"hoge"
のような文字列で保持されます。
数値リテラルの値をint
型として取得したい場合は、strconv.Atoi
関数を用います。一方、文字列リテラルの値をstring
型として取得したい場合は、strconv.Unquote
を用います。
この逆を行いたい場合は、数値リテラルの場合はstrconv.Itoa
関数を、文字列リテラルの場合はstrconv.Quote
を用いるとよいでしょう。
このように、Goの標準ライブラリには便利な関数がたくさん用意されています。みなさんもGoDocを読み込んで便利な関数を発見してみてください。