VCI luaスクリプトでの文字列の連結　deepdive

# フォーマット指定子詳解
この記事では、バーチャルキャストのvciluaスクリプトにおける文字列を扱うテクニックのうち、
[VCI luaスクリプトでの文字列の連結 その１](https://qiita.com/sakkinonana/items/95ef5a38acf6fed97d94)
[VCI luaスクリプトでの文字列の連結　その２](https://qiita.com/sakkinonana/items/99e21032b555a061032b)
で紹介しきれなかった細かいテクニックをご紹介いたします。

## エスケープ文字
luaの文字列では、C言語などの文字列と同様に**エスケープ文字を使うことができます**。これは、TextMeshProでの文字列表示にもきちんと反映されますので、brタグなしでもエスケープ文字で改行することが可能です。エスケープ文字は"\"から始まる主に２文字の文字列です。使うものを以下に紹介します

|エスケープ文字|役割|
|:--:|:--:|
|\n|改行|
|\t|タブ|
| \\ |" \ "の文字そのもの|
|\\"|二重引用符そのもの（文字列中で"をつかうために使う）|
|\\'|引用符そのもの（文字列中で'をつかうために使う）|
|\r|キャリッジリターン（行頭に戻る）|
|\0|null文字|

\nはリッチテキストのオプションをオンにしていなくても使えます。あとはほとんど特殊文字をそのまま表示するために使います。

<!--
## 埋め込み順の指定
プログラムを書いていると、文中に同じ変数の値を複数回登場させたくなることがあります。例えば「100円のリンゴを2つお買い上げです。100かける2で合計200円になります。」という文章があったとします。その場合愚直に書くと以下のようになります。

```lua:愚直に書くパターン
local apple = 100
local num = 2
local str=string.format("%d円のリンゴを%dつお買い上げです。"..
"%dかける%dで合計%d円になります。",apple,num,apple,num,apple*num)
print(str)
```
これはちょっといただけませんね。具体的に何が問題かというと、
* 数値が重複してスマートでない（分量が多くなる）
* フォーマット指定子が多すぎてどれがどれに対応しているかわからなくなる

の二点だと思います。
そこで、埋め込み順の指定をすることによりこれらを解決します。一言でいうと、フォーマット指定子にラベルをつけることができます。
書き方は単純で、フォーマット指定子の%の直後に"数字$"の形で番号を付けます。具体的には、`%1$d`や`%2$f`などです。では、この書き方で先の例を書き直してみましょう。

```lua:埋め込み順の指定するパターン
local apple = 100
local num = 2
local str=string.format("%1$d円のリンゴを%2$dつお買い上げです。"..
"%1$dかける%2$dで合計%3$d円になります。",apple,num,apple*num)
print(str)
```
変数の数がすっきりしましたし、どこを指しているかわかりやすくなりました。
上ではやりませんでしたが、数字を変えれば順番を入れ替えることもできます。
長文になればなるほど重宝すると思います。
-->
# フォーマット指定子の修飾
%dや%sなどのフォーマット指定子(%何々で変数の表示場所を指定する書き方)は[前述](https://qiita.com/sakkinonana/items/99e21032b555a061032b)のようにいくつか種類がありますが、さらに表示の仕方を細かく指定することができます。これをフォーマット指定子の修飾とここでは読んでいますが、よく使うものをいくつかここでご紹介いたします。
## 桁数指定
特に数字などで顕著ですが、必要な桁数を指定したくなることがあります。何と成しに小数を表示すると、
```lua:デフォルトの桁数
print(string.format("視力は%fです",1.0))
```
```lua:出力
視力は1.000000です。
```
これはちょっとくどいですね。合計２桁で十分ですよね。こういう時は桁数を指定します。
桁数の指定の際には"%"と"f"との間に指定する桁数を数字で入れます。
```lua:全体の桁数の指定
print(string.format("視力は%2fです",1.0))
```
```lua:出力
視力は1.0です。
```
いい感じになりましたね。この数字は全体の桁数を指定してくれます。

ふつうの日本人だとこれでよさそうですが、このままだと視力10とかのこの目のいいマオリ族の人が来てしまうとちょっと事情が変わってきます。
```lua:桁数の大きい数字が入ってしまう際
print(string.format("視力は%2fです",10.0))
```
```lua:出力
視力は10です。
```
小数点以下の桁がなくなってしまいます。全体の桁数が変わっても小数点以下の桁数を担保したいことがありますよね。こういう時は以下のようにします。小数点以下の桁数の指定の際には"%"と"f"との間に"."を入れてそのあとに指定する桁数を数字で入れます。先ほどの全体の桁数の指定と複合可能です。

```lua:小数点以下の桁数の指定
print(string.format("視力は%2.1fです",10.0))
```
```lua:出力
視力は10.0です。
```
## 0パディング
等幅フォントと同じように、レイアウトを崩したくないがために数字の位置を固定したいことがあると思います。例えばx:y:zとx2:y2:z2の比較を表示する表を作っている際に、愚直に表示すると下記のようになります
```lua:パディングしないコード
print(string.format("%d:%d:%d",x,y,z))
print(string.format("%d:%d:%d",x2,y2,z2))
```
```lua:パディングしないパターン
10:20:20
5:3:40
```
これだと10未満の数字が混ざってしまうと桁数がバラバラになるため、せっかく表にしても比較するべき数が一見わかりにくい状態になってしまいます。
こういう時にもフォーマット指定子の修飾を使います。
```lua:0パディングするコード
print(string.format("%02d:%02d:%02d",x,y,z))
print(string.format("%02d:%02d:%02d",x2,y2,z2))
```
```lua:0パディングするパターン
10:20:20
05:03:40
```

## 符号
先ほどは値が全部正でしたが、符号が変わることもあります。こういう正負が混ざる時にもレイアウトが崩れる恐れがあります。
```lua:符号を指定しないコード
print(string.format("%d:%d:%d",x,y,z))
print(string.format("%d:%d:%d",x2,y2,z2))
```
```lua:符号を指定しないパターン
-10:20:-20
50:30:40
```

こういう時にには修飾で強制的に符号をつけるようにすれば正負で符号の有無が変化しなくなりレイアウトが維持されます。
```lua:符号を指定するコード
print(string.format("%+d:%+d:%+d",x,y,z))
print(string.format("%+d:%+d:%+d",x2,y2,z2))
```
```lua:符号を指定するパターン
-10:+20:-20
+50:+30:+40
```

## パディング
ちなみに、0でなくスペースによるパディングをすることもできます。0の代わりに半角スペースを入れるだけです。
```lua:スペースパディングするコード
print(string.format("% 2d:% 2d:% 2d",x,y,z))
print(string.format("% 2d:% 2d:% 2d",x2,y2,z2))
```
```lua:スペースパディングするパターン
10:20:20
 5: 3:40
```
## 修飾をパラメトリックに行う
上記説明では、桁数などは決め打ちでハードコードしていましたが、プログラムから制御したりすることもできます。やり方は簡単で、以下のようになります。

```lua:桁数を可変にする
local width = 3
local str = string.format("%."..width.."fドルいただきます。",100)
print(str)

width = 2
str = string.format("%."..width.."fドルいただきます。",100)
print(str)
```
```:出力
100.000ドルいただきます。
100.00ドルいただきます。
```

ここではwidthに3が入っていますが、2を代入してから呼び出してやれば小数点以下２桁までの表示になります。


# table.unpack()を使った可変長文
表示する変数が多い場合は指定文が長くなって煩雑になりがちです。
```lua:unpack()を使わないパターン
local list = {1,2,4,8,16,32,64}
local str = string.format("%d,%d,%d,%d,%d,%d,%d",list[1],list[2],list[3],list[4],list[5],list[6],list[7])
print(str)
```
そこで活躍するのがtable.unpack()関数です。テーブルに入っている要素をすべて吐き出します。
```lua:unpack()を使うパターン
local list = {1,2,4,8,16,32,64}
local str = string.format("%d,%d,%d,%d,%d,%d,%d",table.unpack(list))
print(str)
```
かなりすっきりします。

この時、string.format()は可変長引数なので、指定されている量よりも多く要素が入っていても動きます。
# 参考
https://staff.aist.go.jp/yutaka.ueno/lua/manual4jp.html
https://ocraviutl.fandom.com/ja/wiki/Lua%E3%81%AE%E6%96%87%E5%AD%97%E5%88%97