MikoScript3 言語仕様
文字列リテラル
文字列リテラル(定文字列)は、文字列型の一定のデータを表します。
文字列リテラルには、以下の3形態の表記があります。
・通常文字列
・純粋文字列
・直記文字列
●通常文字列
通常文字列は、下例のように、対象の文字列を二重引用符( " )で囲って表します。
"This is a 通常文字列."
通常文字列は、1行内に記述する必要があります。つまり、二重引用符の囲い中には、
直接、改行コードを入れることはできません。通常文字列内に、改行コードを入れる
には、エスケープ文字の \n を使います。たとえば、
print "1行目\n2行目\n3行目";
を実行すると、
1行目
2行目
3行目
とプリントされます。
エスケープ文字は、各種の制御コードや特別の文字等を表記する場合に使います。
エスケープ文字の表記は、\ で始まり、次にアルファベット1字が続きます。
この2字で1つの特定の文字コードを表します。
この場合のエスケープ文字の一覧表を以下に示します。
表記 値 意味
\a 0x07 ベル
\b 0x08 バックスペース
\e 0x1B エスケープ
\f 0x0C 改頁(フォームフィード)
\n 0x0D 改行(ラインフィード)
\r 0x0A 復帰(キャリッジリターン)
\t 0x09 水平タブ
\v 0x0B 垂直タブ
\0 0x00 ヌル
エスケープ文字では、さらに、次の表記形態で、任意の値の文字コードを表せます。
なお、ここで、N は 16 進数の1桁を表わす1字( 0〜9, A〜F )です。
\xNN 1〜2 桁の 16 進数
\uNNNN 1〜4 桁の 16 進数
\UNNNNNN 1〜6 桁の 16 進数
この形態で表記するのは、ユニコードの値です。以下に、その例を示します。
\x41 「A」
\x7F ( DEL 制御コード )
\u3042 「あ」
\u6625 「春」
\U1D11E (音楽のト音記号)
エスケープ文字の \ の次の文字が、上記以外の場合、その文字自身を表します。
この原則によって、\ は \\ として表わせます。また、" は \" として表わせます。
例えば、
print "二重引用符内の \" と \\ は、\\\" と \\\\ として表わせます";
を実行すると、
二重引用符内の " と \ は、\" と \\ として表わせます
とプリントされます。
エスケープ文字を使うのは、3種の文字列リテラルのうち、通常文字列だけです。
≪補足説明≫
\ 直後に、改行コードがある場合(これはエスケープ文字とは言わない)、
その \ と改行コードは、その文字列には含まれずに、その次の行の先頭からが
その続きになります。文字列が長い場合に、この表記を使うこともできますが、
普通は、後述の連続表記を使います。
●純粋文字列
純粋文字列は、下例のように、$ に続けて対象の文字列を二重引用符で囲って表します。
$"This is a 純粋文字列."
純粋文字列では、二重引用符の囲い中に、エスケープ文字は使えません。従って、\ は
1字で \ 自身を表します。これは、 \ を常用する正規表現やファイルのパスを表記する
時に便利です。たとえば、ブロックコメントに一致する正規表現は、
純粋文字列の場合: $"#m/\*(.|\n)*\*/"
通常文字列の場合: "#m/\\*(.|\\n)*\\*/"
となります。( なお、#m は最小一致を指令するモードです )
また、純粋文字列は、通常文字列と同様に、1行内に記述する必要があります。この制約
は、囲い内の文字列が長くなる場合に、不便なようですが、後述の連続表記を使うと、特
に支障なく書けます。また、この表記ではコメントを添えることができます。たとえば、
$"(\s+)|" // 空白
$"([-+]?\d+)|" // 整数
$"(\a[\a\d]*)" // 変数名
と書いたものは、
$"(\s+)|([-+]?\d+)|(\a[\a\d]*)"
と1つにまとめて書いたものと同じです。
純粋文字列では、囲い内の文字列に、囲い文字を含めることはできません。そのため、囲
い文字は、" だけでなく、' ` / % ! も使えるようになっています。たとえば、囲
い文字として / を使うと、以下のように、" を対象の文字列内に含めることができます。
$/("ABC"|"XYZ")/
どの囲い文字を使う場合でも、囲いの開始文字と終了文字は同じ文字になります。
上例では、囲いの開始に / を使っているので、囲いの終了も / になります。
●直記文字列
直記文字列は、対象の文字列を ## と ## で囲って表します。
この囲いの中は、改行やタブのような特殊なコードでも、エスケープ表記なしに、
そのまま含むことができます。そのため、複数行に渡るような長い文字列も
見た目通りに記述できます。たとえば、
##
→ これは直記文字列です。
→ この表記は長文にも便利です。
##
という直記文字列( → はタブを示す)は、通常文字列では、
"\n\tこれは直記文字列です。\n\tこの表記は長文に便利です。\n"
となります。
直記文字列では、囲い内の文字列に、囲い文字を含めることはできません。そのため、囲
い文字は、## だけでなく、#" #' #` #/ #% #! も使えます。
たとえば、囲い文字として #' を使うと、以下のように、## を対象の文字列内に含める
ことができます。
#'直記文字列内に ## の包含は可能です。#'
どの囲い文字を使う場合でも、囲いの開始文字と終了文字は同じ文字になります。
上例では、囲いの開始に #' を使っているので、囲いの終了も #' になります。
後述の連続表記は、直記文字列の場合でも可能です。また、別の表記形態の文字列との
混在も可能です。たとえば、
##abc## ##いろは## "XYZ" $"123"
は、
"abcいろはXYZ123"
と同じです。
さらに重要なことは、直記文字列の中には、スクリプト式、マクロ、コメントが
書けることです。
スクリプト式は、直記文字列の中に、 ${ スクリプト式 } という形態で入ります。
##計算結果は ${ ( x + 1 ) * ( y - 1 ) } です。##
直記文字列の中のスクリプト式は、その直記文字列の文が実行される時に評価されて、
その評価値に対応する文字列が、${ ... } 部と置き換わります。たとえば、
a = 8;
b = 9;
print ##さて、${a} と ${b} を足すと ${ a + b } になります##;
を、実行すると、
さて、8 と 9 を足すと 17 になります
とプリントされます。また、
v = 123;
s = ##変数 v の16進値は 0x${ v'x(4) } です##;
print s;
を、実行すると、
変数 v の16進値は 0x007b です
とプリントされます。
ここで、注意すべきことは、${ ... } 内に書けるのは、スクリプト式だということです。
スクリプト式は、変数、定数、演算式、関数コールなどで、文法的に、( と ) の丸括弧
で囲えるものです。したがって、${ ... } 内には、if 文や for 文等のスクリプト文は
書けません。また、空も不可で、関数定義なども書けません。
直記文字列内で、$ が特別な意味を持つのは、${ ... } の場合だけで、
$ の次に来る文字が、{ でなければ、通常の文字と同様に扱われます。
マクロは、通常文字列内や純粋文字列内では認識されませんが、直記文字列内では
有効です。たとえば、
#set M マクロ展開文字列
print ##これは、#M です##; // 直記文字列内ではマクロは有効
print "これは、#M です"; // 通常文字列内ではマクロは無効
を実行すると、
これは、マクロ展開文字列 です
これは、#M です
とプリントされます。なお、直記文字列内でも、展開対象のマクロの名前は、
識別名のトークンとして認識されるように記述されている必要があります。
例えば、上例で、
print ##これは、#Mです##;
とすると、マクロ名が、「M」ではなく「Mです」になってしまいます。
「#M」と「です」の間に半角空白を入れているのはそのためです。この空白を
入れたくない時は、例えば、次のようにします。
print ##これは、#M#--#です##;
ここで使っている #- と -# は、コメントです(詳細後述)。
次に、直記文字列内の ${ ... } 部でマクロを使った例を示します。
#set Age( a, b ) ${ #a }の体力年齢は ${ #b - 5 } 才です
x = 25;
print #`#Age( "太郎", x )#`;
を実行すると、
太郎の体力年齢は 20 才です
とプリントされます。
通常のコメントは、文字列内では、無効ですが、直記文字列内では、以下の範囲が、
直記文字列内専用のコメント部になります。
・#- から -# まで
・#- から改行コードまで
このコメント部は、プログラムの翻訳時に単に読み飛ばされるだけで、直記文字列には
含まれません。たとえば、
print
##
ここから、#- 直記文字列内専用のコメント -# です。
ここから、#- 直記文字列内専用のコメント
改行コードまでがコメントです。
/* 通常のコメント */ は、無効です。
##;
を実行すると、
ここから、 です。
ここから、改行コードまでがコメントです。
/* 通常のコメント */ は、無効です。
とプリントされます。
なお、#- から行末までのコメントの場合、改行コードはコメントに含まれるので、
その行は次行に改行なしで連結されることになります。
直記文字列の中で、# 自身を表わすには、\# とします。
また、$ 自身を表わすには、\$ とします。
直記文字列の中で、\ の次が改行コードの場合、つまり、\ が行末にある場合、
その \ と改行コードは、プログラムの翻訳時に読み飛ばされて、
その直記文字列のデータには含まれません。
直記文字列の中の \ は、以上の場合を除いて、つまり、
\ の次が # $ 改行コード 以外の場合、特別な意味はなく、\ 自身になります。
直記文字列は、内部的には、${ スクリプト式 } で区切られます。
この各区切り間に書ける文字列の字数は、最大 65535 字までという制限があります。
たとえば、
##<文字列部1>${...}<文字列部2>${...}<文字列部3>##
のような場合、<文字列部1>, <文字列部2>, <文字列部3> に書ける字数は、
それぞれ、最大 65535 字までです。
なお、${ スクリプト式 } が生成する文字列の長さには、制限はありません。
●文字列リテラルの連続表記
文字列リテラルは、どの表記形態の文字列でも、空白を挿んで連続する場合、
文法的には、1つの定文字列として扱われます。
たとえば、"ABC" "xyz" は、"ABCxyz" と書くのと同じです。
また、"111" "222" "333" は、"111222333" と書くのと同じです。
さらに、改行やコメントを挿んだ以下のような表記も可能です。
"文字列(1)\n" // 注釈(1)
"文字列(2)\n" // 注釈(2)
"文字列(3)\n" // 注釈(3)
この場合、
"文字列(1)\n文字列(2)\n文字列(3)\n"
と書くのと同じです。
●まとめ
ここで、各文字列表記形態のまとめと補足事項を掲載します。
| 通常文字列 | 純粋文字列 | 直記文字列 |
囲い文字 | "..." | $"..." (*1) | ##...## (*2) |
表記例 | "ABCいろは" | $"(A|B)\d+" | ##A=${X+Y}## |
\エスケープ | 有効 | 無効 (*3) | 無効 |
#マクロ | 無効 | 無効 | 有効 |
${スクリプト式} | 無効 | 無効 | 有効 |
#-コメント-# | 無効 | 無効 | 有効 |
連続表記 | 可 | 可 | 可 |
" の表記 | \" | 不可 (*4) | " |
\ の表記 | \\ | \ | \ (*5) |
$ の表記 | $ | $ | $ (*6) |
# の表記 | # | # | \# (*7) |
改行直前の \ (*8) | 行連結 | \ 自身 | 行連結 |
強制終端 (*9) | NUL,CR,LF,EOF | NUL,CR,LF,EOF | EOF |
記述可能行範囲 | 1行内 | 1行内 | 多行 |
最大字数 (*10) | 65535字 | 65535字 | 65535字/区間 |
(*1) $ の次の記号は " ' ` / % ! が選択できるので、以下の囲いも可能
$'...' $`...` $/.../ $%...% $!...!
(*2) # の次の記号は " ' ` / % ! が選択できるので、以下の表記も可能
#"...#" #'...#' #`...#` #/...#/ #%...#% #!...#!
(*3) ここでの「\エスケープ」は、文字列表記に関するもので、
正規表現での「\エスケープ」とは無関係。
(*4) 囲いが $"..." 場合、その中に " を含めるのは不可。
囲いがそれ以外(例えば「$/.../」)の場合は、" をそのまま記述可。
(*5) 直記文字列内では、\ の次の文字が、# $ 改行コード以外の場合に、
\ はそのまま記述可。
(*6) 直記文字列内では、$ の次の文字が、{ 以外の場合に、$ はそのまま記述可。
(*7) 直記文字列内では、# の次が、マクロ識別名、囲い文字、専用コメント以外なら、
# は通常文字扱いになりますが、直記文字列内で # 自身を表わす場合は、
慣習上、一律に \# と書くようにする方が良いでしょう。
(*8) 通常文字列と直記文字列では、改行直前に \ があれば、\ と改行コードを
含めないで、その行は次行に連結されます。
(*9) 文字列は、囲いの終りがなくても、表中の文字コードまたは条件に遭遇した場合、
強制的に終了します。表中の記号の意味は以下の通り。
NUL,CR,LF: それぞれ、0x00,0x0D,0x0A の値の ASCII コード
EOF: ファイル終端
(*10) 連続表記の場合でも、その総計字数が、この最大字数を超えられません。
●注意事項
・本言語の文字列は、あくまで文字列型のデータであって、C言語のように、
文字の配列になるわけではありません。
・文字列を文字の配列として扱いたい場合は、純粋配列を使います。詳細は、以下参照。
・純粋配列の要素データ上の文字コード列の操作
・\0 を含む文字列には注意が必要です。\0 は、通常、文字列の終端として扱います。
このため、たとえば、
print "abc\0xyz";
を実行しても、
abc
としかプリントされません。