区切り文字

区切り文字（英語: delimiter、デリミタ）は、コンピュータ言語やデータ通信において独立した領域の境界を特定するために入れられる文字である。例えば、コンマ区切りの文字列において、コンマ (,) は各フィールドの境界を表す「フィールド区切り文字」の役割をしている。 区切り文字は、データストリームで境界を指定する方法の1つである。別の方法として、各フィールドの先頭にフィールド長を記述する方法もある。 区切り文字は以下の2種類に分けられる。 フィールド区切り文字・レコード区切り文字（例: コンマや改行） 範囲指定区切り文字（例: 括弧やダブルクォート） フィールド区切り文字はデータフィールドを分離し、レコード区切り文字はフィールドのグループを分離する。 例えば、CSVファイルはコンマをフィールド間の区切り文字として、改行コードをレコード間の区切り文字として使用している。 以下は、CSVファイルのフォーマットを使用した簡単なフラットファイルデータベースのテーブルの例である。 fname,lname,age,salary nancy,davolio,33,$30000 erin,borakova,28,$25250 tony,raphael,35,$28700 範囲指定区切り文字は、テキストの範囲の最初と最後を示すものである。 よく使われる範囲指定区切り文字には、以下のものがある。 慣習的に、プラットフォームによって特定の区切り文字が使われる。以下に、そのいくつかの例を示す。 プログラミング言語 （プログラミング言語の比較 (文法)（英語版）も参照） フィールド区切り文字・レコード区切り文字（ASCII、制御文字も参照） 区切り文字衝突（英語: delimiter collision）とは、テキスト中のある文字が区切り文字として解析され、意図しない動作を引き起こす問題である。例えばCSVファイルの場合、フィールドにコンマを含む値（例: 38,915円87銭）を入れようとするとフィールド区切り文字衝突が起こり、複数行の値を入れようとするとレコード区切り文字衝突が起こる。XMLの場合、フィールドに山括弧を含む値を入れようとすると区切り文字（フィールド区切り文字・レコード区切り文字のどちらも）衝突が起こる。テキストファイルではフィールド区切り文字・レコード区切り文字の衝突はよく発生する。 悪意のあるユーザーや攻撃者は、この問題を故意に利用しようとするかもしれない。従って、区切り文字衝突は、セキュリティホールやエクスプロイトの原因となり得る。悪意のあるユーザーはSQLやHTMLのような言語で、区切り文字衝突を利用してSQLインジェクションやクロスサイトスクリプティングのような攻撃を行う。 区切り文字衝突は非常に一般的な問題なので、それを回避する様々な方法が考案されている。 データストリームに現れそうにない文字（または文字列）を区切り文字として選ぶことによって、問題を回避する方法がある。この方法は多くの場合は通用するが、その文字がデータストリームに現れる確率はゼロではなく、また、悪意のある攻撃に対して安全ではない。よって、この方法は通常はとられない。 ASCIIとUnicodeの文字セットではこの問題を回避するために、区切り文字として使用するための非表示の制御文字を用意している。それらの文字はASCIIで28 (0x1C) から31 (0x1F) に割り当てられている。 ASCII 31のユニット分離文字をフィールド区切り文字として、ASCII 30のレコード分離文字をレコード区切り文字として使用することで、フィールド区切り文字・レコード区切り文字の問題は解決する。 区切り文字衝突の他の解決法として、エスケープ文字を使用する方法がある。これは、区切り文字の前にエスケープ文字を置くことで、その文字は区切り文字として使用する意図ではないことを明示するものである。言語設計の見地からはこれで十分であるが、以下のような欠点もある。 大量のエスケープ文字が入ることで可読性が低くなる。例えば、Perlの正規表現の中で「/」という文字自体を使用したいときは「\/」のように書くが、「//」のように2つ続く場合は「\/\/」のようになる。 エスケープ文字として使われる文字を文字通りの文字として表現するたの表記法必要である。例えば、HTMLではエスケープ文字である「&」を文字通りの文字として表現するために「&amp;」という表記法がある。またC言語ではエスケープ文字である「\」を文字通りの文字として表現するために「\\」という表記法がある。 入力するのは簡単だが、その言語をよく知らない人によって理解ができなくなる。 エスケープシーケンスはエスケープ文字と似ているが、衝突する文字そのものの代わりに別の文字列を使用する。 例えば、Perlにおいて文字列リテラルの中にダブルクォートを含ませたいとき、以下のように書く。 print "Nancy said \x22Hello World!\x22 to the crowd."; ### ダブルクォートの代わりにエスケープシーケンス \x22 を使用 エスケープ文字を使うと以下のようになる。 print "Nancy said \"Hello World!\" to the crowd."; ### エスケープ文字を使用 エスケープシーケンスの欠点は、それぞれの文字を意味するコードを覚える必要があることである（文字参照を参照）。 2種類の区切り文字は、区切り文字衝突を避けるためのエスケープ文字やエスケープシーケンスとは別の手段を提供する。いくつかの言語では、シングルクォート (') とダブルクォート (") の2種類を文字列リテラルの区切り文字として使えるようになっている。 Perlでは以下のようになる。 print 'Nancy said "Hello World!" to the crowd.'; このように、エスケープを使わずに表現でき、可読性やコードを覚えなければいけない問題が解決する。しかしこの方法は、文字列が「両方の」種類の文字を含む場合には使えない。 区切り文字衝突を避けるためのエスケープ文字やエスケープシーケンスとは別の手段として、区切り文字の繰り返しがある。これは、衝突する文字を重ねて書く方法である。例えば、区切り文字にダブルクォートを用いるVisual Basicでは、次のようになる。区切り文字の繰り返しは、区切り文字のエスケープと似ている。 print "Nancy said ""Hello World!"" to the crowd." 文字列リテラル内のダブルクォートを2回続けて書くことで、区切り文字でないことを示している。2種類の区切り文字同様、エスケープを使わずに表現できる。しかし、複数のクォートが連続して現れる場合には可読性が低くなる。例えば、上記のソースコード自体を表示させたい場合は、以下のようになる。 print "print ""Nancy said """"Hello World!"""" to the crowd.""" 2種類の区切り文字は2種類の範囲指定区切り文字を使用したが、3種類以上の区切り文字はその種類をさらに増やす。 以下はPerlでの例である。 print qq^Nancy doesn't want to say "Hello World!" anymore.^; print qq@Nancy doesn't want to say "Hello World!" anymore.@; print qq(Nancy doesn't want to say "Hello World!" anymore.); いずれも、クォート演算子を用いることにより、意図した通りの出力がされる。どんな文字でも区切り文字の働きをさせることができる。この方法がより柔軟であるが、ほとんどの言語は対応していない。PerlとRubyは対応している。 コンテントバウンダリ (content boundary) は、マルチパートのメッセージにおいて、メッセージ中に現れないような文字列をパートの区切り文字として指定する方法である。 区切り文字は通常、統計学的に本文中に現れそうにないランダムな文字列から生成する。この後に、特定可能なマーク（UUID、タイムスタンプなど）が続く場合もある。区切り文字が本当に本文中に現れていないか確認することもある。この手法は、区切り文字を短かく、単純なものにすることができ、人間による可読性も向上する。（MIME、ヒアドキュメントも参照） いくつかのプログラミング言語やコンピュータ用言語では、テキスト中の独立した領域の境界を指定する手段として、空白文字による区切り文字やインデントが使用可能である。 正規表現を指定する際、Perlで「マッチ（一致）」と「置換」のために構文を単純化するのに代替の区切り文字が用いられる。 例えば、Perlでの単純なマッチの操作の構文は以下のようになる。 $string1 = 'Nancy said "Hello World!" to the crowd.'; # 対象の文字列を指定 print $string1 =~ m/[aeiou]+/; # 1つ以上の母音にマッチ この構文は、区切り文字の衝突を避けるために、区切り文字を柔軟に変更できる。 $string1 = 'Nancy said "http://Hello/World.htm" is not a valid address.'; # 対象の文字列を指定 print $string1 =~ m@http://@; # 代替の区切り文字を使用したマッチ print $string1 =~ m{http://}; # 別の区切り文字を使用。上と同じ結果になる。 print $string1 =~ m!http://!; # 別の区切り文字を使用。上と同じ結果になる。 ヒアドキュメントは、特別な終了文字列を指定することによって、任意の内容が含められるようにしている。PHP、Bash、Perlなどの多くの言語が対応している。ヒアドキュメントは、終了文字列の指定から始まり、改行の後、終了文字列が現れるまで続く。 以下はPerlによる例である。 print <<ENDOFHEREDOC; It's very hard to encode a string with "certain characters". Newlines, commas, and other characters can cause delimiter collisions. ENDOFHEREDOC 上記のコードを実行すると、以下のように出力される。 It's very hard to encode a string with "certain characters". Newlines, commas, and other characters can cause delimiter collisions. 内容には、（終了文字列そのもの以外は）どんな文字でも含めることができる。 主にバイナリデータのテキスト・エンコーディングのためのメカニズムとして使われるが、ASCII-armorは、いくつかの状況で区切り文字の衝突を避けるためにも使えるプログラミングとシステム管理のテクニックである。 この手法は複雑なため、小さなアプリケーションと単純なデータ記憶フォーマットにふさわしくない。区切り文字が送られたデータで現れないことを確実とするために、特別なエンコーディング・スキーム（例えばbase64）を使用する。 この手法はマイクロソフトのASP.NETなどで使われており、そのシステムの"VIEWSTATE"コンポーネントと密接に関係している。 以下の簡略化された例は、この技術が実際にはどのように機能するかについて示す。 次のコード断片は、VIEWSTATEの値がHTMLタグの区切り文字 (") と衝突する例である。このコードは"Well-formed"ではなく、正しく解釈されない。 <input type="hidden" name="__VIEWSTATE" value="BookTitle:Nancy doesn't say "Hello World!" anymore." /> 次のコード断片は同じHTMLタグを示しているが、VIEWSTATEの値をbase64でエンコードすることによって、区切り文字と衝突する文字が取り除かれている。 <input type="hidden" name="__VIEWSTATE" value="Qm9va1RpdGxlOk5hbmN5IGRvZXNuJ3Qgc2F5ICJIZWxsbyBXb3JsZCEiIGFueW1vcmUu" /> 次のコード断片は、同じHTMLタグをパーセントエンコーディングによって表した例である。 <input type="hidden" name="__VIEWSTATE" value="BookTitle:Nancy%20doesn%27t%20say%20%22Hello%20World!%22%20anymore." /> どんな文字がオリジナルの（デコードされた）テキストに現れるかに関係なく、この手法は区切り文字の衝突を防止し、非互換の文字がHTMLコードに現れないことを確実にする。 区切り文字としたい文字列中に存在しない文字を特定してその文字を区切り文字とし、区切り文字とした文字が何であるかを決められた位置（例えば、１文字目とか、最後の位置）に配置する。 例えば、「\10,000」「\300」「aaa;」という文字列がある場合、カンマやセミコロンは区切り文字にならないから、それらの文字列中に存在しない文字、例えば「>」を区切り文字とし、「>\10,000>\300>aaa;>」とする。 Delimiter-separated values（英語版） 文字列リテラル エスケープシーケンス