文字列内埋め込み要素の展開¶
概要¶
文字列の中に変数や関数を埋め込んで、これらの実行結果を当該位置へ挿入できる。埋め込み方は「範囲付き展開」と「名称最長一致展開」の 2 種類。
範囲付き展開¶
要素を %( ) で囲んで埋め込む。
request
{
_i = "pen"
"This is a %(_i)."
}
request を実行すると、"This is a pen." が出力される。%( ) はいわゆる eval(文字列をスクリプトコードと解釈して実行する)のような動作を行う。単一の関数や変数だけでなく、数式も埋め込める。
request
{
"1+2+3は%(1+2+3)です。"
}
request は "1+2+3は6です。" を出力する。
%( ) の中にはダブルクォートを含められない。したがって、文字列を含む数式は埋め込めない。次はエラーになる。
request
{
"This is a %(_i = "pen")."
}
このような場合は、埋め込みを使用せず通常の数式として結合する。
request
{
"This is a " + (_i = "pen") + "."
}
ブラケット ( ) による演算順序制御は、範囲付き展開でも同様に働く。次の例を見てほしい。
request
{
"遊星「%(_i = planet)」は遠い。この遊星は%(color(_i))色をしている。"
}
planet
{
"mars"
"saturn"
"pluto"
}
color
{
case _argv[0] {
when "mars"; "red"
when "saturn"; "yerrow"
when "pluto"; "blue"
others; "unknown"
}
}
最も ( ) が深いのは color(_i) の引数なので、_i = planet の前に color が呼び出されてしまい、_i がまだ空のため "unknown" になる。ブラケットを過剰に付与して演算順序を調整する。
"遊星「%((_i = planet))」は遠い。この遊星は%(color(_i))色をしている。"
これで矛盾のない文字列が得られる。
特徴:
- 複雑な式や数学演算をサポートする
- 文字列内にダブルクォートを含められない
- 辞書の読み込み時に静的に解析されるため、DICLOAD などで後から定義した関数は認識されない。どうしてもそのような使い方をしたい場合は、EVAL の利用を検討すること
名称最長一致展開¶
( ) を付けず、単に % のみでも埋め込み展開は機能する。
request
{
o = "pen"
obj = "eraser"
object = "world"
"This is a %object."
}
obje
{
"television"
}
展開対象は、% 以降の文字列に一致する最も長い名前を持った変数 / 関数になる。上の例の場合、もっともよく一致するのは変数 object なので、これが採用される。結果は "This is a world." になる。
変数は刻々と作成されたり消えたりするので、展開対象が状況によって変化する。これは範囲付き展開には見られない特徴。
request
{
val = "red"
trans
--
value = "blue"
trans
}
trans
{
"%value"
}
trans は 2 度実行されるが、最初と 2 度目では "%value" の動きが変わる。最初は変数 val + "ue"、2 度目は変数 value と解釈される。request の出力は "redueblue" になる。
展開結果の再利用¶
%[ ] という書式で、過去の展開結果を再利用できる。
request
{
"「%planet」は遠い。「%city」も遠い。もっとも%[1]になら行けなくもない。"
}
planet
{
"mars"
"saturn"
"pluto"
}
city
{
"newyork"
"moscow"
"madrid"
}
%[i] は 0 オリジンで i 番目の展開結果を得る。上の例では、%[0] が %planet の、%[1] が %city の展開結果を示している。
%[ ] は範囲付き展開では使えない。範囲付き展開で過去の結果を再利用したい場合は、それを変数へ入れる。
速度¶
名称最長一致による展開は、実行するたびに展開対象を検索しなおすので、範囲付き展開と比べて動作速度が劇的に遅い。本当に必要な場合は別として、通常は範囲付き展開を利用すること。
名前を読み込み時に確定する¶
名称最長一致展開は、実行した時点で存在する変数で名前を探す。そのため、URL などの % を含む文字列が、ある時点から急に置き換わることがある。
"https://example.com/?p=100%off" // 変数 o や of が作られると、その値に置き換わる
設定ファイルに embed.lazy, off と書くと(Tc604-1以降)、カッコなしの % の後の名前を辞書の読み込み時に確定する。
- 名前は、ユーザー関数・システム関数と、辞書の式に名前が書かれたグローバル変数(
EVALなどで実行した式も含む)の最長一致で決める。セーブファイルから復元しただけの変数や、LETTONAMEで作っただけの変数は対象にならない。こうした変数を埋め込むときは%(名前)と書く - 確定した変数がまだ値を持っていないときは、空文字列になる(
%名前のまま残らない) - どの名前とも一致しなかったものは、
%を含めてそのまま文字列として扱う。英字や全角文字で始まるものには警告 W0031 を出す。%E3のような 16 進数 2 桁(URL エンコード)や、数字・記号で始まるものは警告しない - ローカル変数(
%_name)は、従来どおり実行時に名前を探す %[i]の番号は、文字列のまま残ったものも 1 つと数える(embed.lazyの設定で番号は変わらない)