文字列リテラル

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

文字列リテラルまたは匿名文字列[1]は、コンピュータプログラムのソースコードで文字列値を表現するためのリテラルの一種です最近のプログラミング言語では、これは通常、引用符で囲まれた文字のシーケンス(正式には「括弧で囲まれた区切り文字」)です。ここで、は値を含む文字列リテラルです。引用符は値の一部ではないため、エスケープなどのメソッドを使用する必要があります。区切り文字の衝突の問題を回避し、区切り文字を許可するシーケンスx = "foo""foo"foo文字列に埋め込まれること自体。ただし、文字列リテラルを指定するための代替表記法は多数あり、特により複雑な場合は、正確な表記法は問題の個々のプログラミング言語によって異なります。それにもかかわらず、ほとんどの最新のプログラミング言語が従う一般的なガイドラインがあります。

構文

括弧で囲まれた区切り文字

最新のプログラミング言語のほとんどは、角かっこ区切り文字バランスのとれた区切り文字)を使用して文字列リテラルを指定します。二重引用符は、使用される最も一般的な引用符区切り文字です。

"やあ!"

空の文字列は、文字通り、間に文字がまったくない引用符のペアで記述されます。

""

一部の言語では、二重引用符の代わりに一重引用符の使用が許可または義務付けられています(文字列は同じ種類の引用符で開始および終了する必要があり、引用符の種類によってセマンティクスがわずかに異なる場合とそうでない場合があります)。

'やあ!'

これらの引用符はになっておらず(同じ文字がオープナーとクローザーとして使用されています)、これは初期のコンピューター入出力デバイスの前身であった タイプライター技術からの二日酔いです。

正規表現に関して、基本的な引用符で囲まれた文字列リテラルは次のように与えられます。

"[^"] * "

これは、文字列リテラルが次のように記述されることを意味します:引用符、その後にゼロ、1つ、またはそれ以上の非引用符文字、その後に引用符実際には、これは、エスケープ、他の区切り文字、および改行の除外によって複雑になることがよくあります。

ペアの区切り文字

多くの言語では、開始区切り文字と終了区切り文字が異なるペアの区切り文字が提供されています。これらはネストされた文字列も許可することが多いため、ペアになっている限り区​​切り文字を埋め込むことができますが、ペアになっていない終了区切り文字を埋め込むための区切り文字の衝突が発生します。例としては、のように括弧を使用するPostScript(The quick (brown fox))や、開始区切り文字としてバックティック( `)を使用するm4 、終了区切り文字としてアポストロフィ( ')を使用するm4などがあります。Tclでは、または;のように、引用符(補間された文字列の場合)と中括弧(生の文字列の場合)の両方を使用できます。これは、Unixシェルでの単一引用符とCでの中括弧の使用に由来します。"The quick brown fox"{The quick {brown fox}}複合ステートメントの場合、コードのブロックは構文的に文字列リテラルと同じものであるため、区切り文字がペアになっていることが、これを実現可能にするために不可欠です。

Unicode文字セットには、テキストで使用される一重引用符と二重引用符の両方のペア(個別の開始と終了)バージョンが含まれていますが、ほとんどが英語以外の言語で使用されますが、プログラミング言語ではほとんど使用されません(ASCIIが推奨され、これらは含まれていないため) ASCIIで):

"やあ!"
 'やあ!'
 "やあ!"
 "やあ!"

ペアの二重引用符はVisualBasic .NETで使用できますが、他の多くのプログラミング言語はそれらを受け入れません。ペアになっていないマークは、さまざまなキーボードで入力しやすいため、互換性のために推奨されます。したがって、許可されている言語でも、多くのプロジェクトでソースコードの使用が禁止されています。

空白の区切り文字

文字列リテラルは改行で終了する場合があります。

一例はMediaWikiテンプレートパラメータです。

{{Navbox
 | name = Nulls
 | title = [[wikt:Null | Nulls]] in [[computing]]
 }}

複数行の文字列には特別な構文がある場合があります。

YAMLでは、文字列リテラルは空白とインデント の相対的な配置によって指定できます。

    --title  : YAML本文複数行の文字列の例| これは複数行の文字列です。「特別な」メタ文字がここに表示される場合があります。この文字列の範囲はインデントで表されます。 
       
        
        
        
        

区切り文字なし

PerlやPHPなどの一部のプログラミング言語では、コンテキストによっては区切り文字なしで文字列リテラルを使用できます。次のPerlプログラムでは、たとえばred、、、greenおよびblueは文字列リテラルですが、引用符で囲まれていません。

%map  =   =>  0x00f   =>  0x0f0   =>  0xf00 );

Perlは、ほとんどのコンテキストで、英数字の予約されていないシーケンスを文字列リテラルとして扱います。たとえば、次の2行のPerlは同等です。

$ y  =  "x" ; 
$ y  =  x ;

宣言型表記

元のFORTRANプログラミング言語(たとえば)では、文字列リテラルはいわゆるホレリス表記で記述されていました。この表記では、文字数の10進数の後に文字Hが続き、次に文字列の文字が続きます。

35HAnのホレリス 文字リテラル   

この宣言型表記スタイルは、文字列の両側でバランスの取れた「括弧で囲まれた」文字を使用する必要がないため、 括弧で囲まれた区切り文字の引用符とは対照的です。

利点:

欠点:

ただし、これは、ほとんどの場合のようにプレフィックスがアルゴリズムによって生成される場合の欠点ではありません。[要出典]

コンストラクター関数

C ++には2つのスタイルの文字列があります。1つはCから継承され(で区切られます)、もう1つはC ++標準ライブラリで"より安全です。std::stringこのstd::stringクラスは、文字列リテラルが他の言語で使用されるのと同じ方法で頻繁に使用され、柔軟性と安全性が高いため、Cスタイルの文字列よりも好まれることがよくあります。ただし、通常はメモリを動的に割り当てるため、文字列リテラルのパフォーマンスが低下しstd::string、実行時にCスタイルの文字列リテラルをコピーする必要があります。

C ++ 11より前は、C ++文字列のリテラルはありませんでした(C ++ 11ではリテラル"this is a C++ string"ss最後にを使用できます)。そのため、通常のコンストラクター構文が使用されました。次に例を示します。

  • std::string str = "initializer syntax";
  • std::string str("converting constructor syntax");
  • std::string str = string("explicit constructor syntax");

これらはすべて同じ解釈です。C ++ 11以降、新しいコンストラクター構文もあります。

  • std::string str{"uniform initializer syntax"};
  • auto str = "constexpr literal syntax"s;

区切り文字の衝突

引用符を使用するときに、区切り文字自体を文字列リテラルで表現したい場合、区切り文字の衝突の問題が発生します。たとえば、区切り文字が二重引用符である場合"""、2番目の引用符は文字列の値ではなく文字列リテラルの終わりとして解釈されるため、文字列で二重引用符自体を単純に表すことはできません。同様に、次のように記述することもできません"This is "in quotes", but invalid."。代わりに、中央の引用符で囲まれた部分は引用符の外側として解釈されます。さまざまな解決策があり、その最も一般的な目的は、"\""またはなどのエスケープシーケンスを使用する"This is \"in quotes\" and properly escaped."ことですが、他にも多くの解決策があります。

Tclの中括弧などのペアの引用符は、などのネストされた文字列を許可しますが、のように{foo {bar} zork}不均衡な終了区切り文字を単純に含めることはできないため、区切り文字の衝突の問題を解決しません{}}

倍増

PascalBASICDCLSmalltalkSQLJFortranなどの多くの言語は、文字列リテラル自体の一部となることを目的とした引用符を 2倍にすることで、区切り文字の衝突を回避します。

  'このPascal文字列' 'には2つのアポストロフィが含まれています' ' '
  「私は、「あなたは私を聞くことができますか?」と言いました。」

二重引用符

FortranModula-2JavaScriptPythonPHPなどの一部の言語では、複数の引用符区切り文字を使用できます。2つの可能な区切り文字の場合、これは二重引用符として知られています。通常、これは、プログラマーが一重引用符または二重引用符のいずれかを交換可能に使用できるようにすることで構成されます。各リテラルはどちらか一方を使用する必要があります。

  「これはジョンのリンゴです。」
  「私は「聞こえますか?」と言いました。」

ただし、これでは、両方の区切り文字を含む単一のリテラルを使用することはできません。これは、いくつかのリテラルと文字列連結を使用することで回避できます

  「私は、「これは」 +  「ジョンの」 +  「リンゴ」と言いました。

Pythonには文字列リテラルの連結があるため、演算子がなくても連続する文字列リテラルは連結されるため、これは次のように減らすことができます。

  「私は言った、「これは」「ジョンの」「リンゴ」です。」

Dは、いくつかの引用符区切り文字をサポートします。このような文字列は、他の区切り文字(()<> {}または[]のいずれか)で開始q"[および終了するか、同様に終了します。]"Dは、同様の構文を介してヒアドキュメントスタイルの文字列もサポートします。

shPerlなどの一部のプログラミング言語では、文字列補間を実行するかどうかなど、処理が異なるさまざまな区切り文字があります。したがって、使用する区切り文字を選択する際には注意が必要です。以下のさまざまな種類の文字列を参照してください

複数引用符

さらなる拡張は、複数引用符の使用です。これにより、作成者は、文字列リテラルの境界を指定する文字を選択できます。

たとえば、Perlでは:

qq ^私は「聞こえますか?」と言いました^ 
qq @私は「聞こえますか?」と言いました@ 
qq§私は「聞こえますか?」と言いました§

すべてが望ましい結果を生み出します。この表記はより柔軟ですが、サポートしている言語はほとんどありません。Perlの他に、Ruby(Perlの影響を受ける)とC ++ 11もこれらをサポートしています。C ++ 11では、生の文字列は、で始まり、R"delimiter(で終わるさまざまな区切り文字を持つことができます)delimiter"区切り文字の長さは0〜16文字で、空白文字、括弧、または円記号を除く基本的なソース文字セットの任意のメンバーを含めることができます。複数引用符の変形は、ヒアドキュメントスタイルの文字列の使用です。

Lua(5.1以降)は、特に長いコメントや埋め込み文字列のネストを可能にするために、限定された形式の複数引用符を提供します。通常、とを使用[[]]てリテラル文字列を区切ります(最初の改行は削除され、それ以外の場合はraw)が、開き角かっこには任意の数の等しい記号を含めることができ、同じ数の記号を持つ閉じかっこのみが文字列を閉じます。例えば:

local  ls  =  [= [
この表記はWindowsパスに使用できます:
local path = [[C:\ Windows \ Fonts]] 
] =]

複数引用符は、引用符などの通常の区切り文字を含む正規表現で特に役立ちます。これにより、区切り文字をエスケープする必要がなくなります。初期の例はsedで、置換コマンドでは、デフォルトのスラッシュ区切り文字をのように別の文字に置き換えることができますs/regex/replacement//s,regex,replacement,

コンストラクター関数

現代語ではめったに使用されない別のオプションは、リテラルで表すのではなく、関数を使用して文字列を作成することです。計算は解析時ではなく実行時に行われるため、これは一般に現代語では使用されません。

たとえば、初期の形式のBASICには、ここにリストされているエスケープシーケンスやその他の回避策が含まれていなかったため、代わりにCHR$、引数に対応する文字を含む文字列を返す関数を使用する必要がありました。ASCIIでは引用符の値は34であるため、ASCIIシステムで引用符を使用して文字列を表すには、次のように記述します。

「私は言った、「+ CHR $ 34 + 「聞こえますか?」+ CHR $ 34       

Cでは、sprintf%c文字」形式指定子を介して同様の機能を使用できますが、他の回避策がある場合、これは通常使用されません。

sprintf "これは%cinの引用符です。%c " 34、34 ;  

これらのコンストラクター関数は、印刷されない文字を表すためにも使用できますが、通常はエスケープシーケンスが代わりに使用されます。std::string同様の手法をC ++で文字列化演算子 を使用して使用できます。

エスケープシーケンス

エスケープシーケンスは、区切り文字、非印刷文字(バックスペースなど)、改行、空白文字(視覚的に区別できない)など、直接表現するのが困難で、長い歴史を持つ文字を表現するための一般的な手法です。したがって、これらは文字列リテラルで広く使用されており、エスケープシーケンスを(単一の文字または文字列全体に)追加することは、エスケープとして知られています

直接含めることが困難または不可能な文字をエンコードするために、接頭辞として1文字が選択されます。最も一般的には、これはバックスラッシュです。他の文字に加えて、重要な点は、バックスラッシュ自体をダブルバックスラッシュとしてエンコード\\でき、区切られた文字列の場合、区切り文字自体をエスケープすることでエンコードできることです。たとえば、\"「」などです。このようなエスケープされた文字列の正規表現は、次のように指定できます。 、ANSI C仕様にあるように:[2] [a]

"(\\。| [^ \\"])* "

「引用符。その後にエスケープ文字(バックスラッシュの後に何か、場合によってはバックスラッシュまたは引用符)、または非エスケープ文字、非引用符のいずれかが0個以上続く。引用符で終わる」–唯一の問題は区別することです。バックスラッシュが前に付いた引用符から引用符を終了します。バックスラッシュ自体はエスケープできます。\uFFFFエスケープスキームによっては 、などのバックスラッシュの後に複数の文字を続けることができます。

次に、エスケープされた文字列自体を字句解析して、エスケープされた文字列をそれが表すエスケープされていない文字列に変換する必要があります。これは、コンピューター言語の全体的な字句解析の評価フェーズで行われます。全体的な言語の字句解析プログラムの評価者は、エスケープされた文字列リテラルに対して独自の字句解析を実行します。

特に、通常は文字列定数を終了する文字をエンコードできる必要があります。さらに、エスケープ文字自体を指定する方法が必要です。エスケープシーケンスは必ずしもきれいで使いやすいとは限らないため、多くのコンパイラは一般的な問題を解決する他の手段も提供しています。ただし、エスケープシーケンスはすべての区切り文字の問題を解決し、ほとんどのコンパイラはエスケープシーケンスを解釈します。エスケープ文字が文字列リテラル内にある場合、これは「これがエスケープシーケンスの開始です」という意味です。すべてのエスケープシーケンスは、文字列に直接配置される1文字を指定します。エスケープシーケンスに必要な実際の文字数はさまざまです。エスケープ文字はキーボードの左上にありますが、エディターがそれを変換するため、文字列に直接テープで変換することはできません。

多くの言語は、文字列リテラル内でのメタ文字の使用をサポートしています。メタ文字の解釈はコンテキストと言語によって異なりますが、通常、印刷文字または非印刷文字を表すための一種の「処理コマンド」です。

たとえば、C文字列リテラルでは、円記号の後に「b」、「n」、「t」などの文字が続く場合、これはそれぞれ非印刷のバックスペース改行、またはタブ文字を表します。または、円記号の後に1〜3桁の8進数が続く場合、このシーケンスは、指定されたASCIIコードで任意の文字を表すものとして解釈されます。これは後で拡張され、より最新の16進文字コード表記 が可能になりました。

「私が言った、\ t \ t \ x22Ca n聞こえますか?\ x22 \ n "
エスケープシーケンス Unicode 文字列に配置されたリテラル文字
\ 0 U + 0000 ヌル文字[3] [4]
(通常、\ ooo 8進表記の特殊なケースとして)
\ a U + 0007 アラート[5] [6]
\ b U + 0008 バックスペース[5]
\ f U + 000C フォームフィード[5]
\ n U + 000A 改行[5](またはPOSIXの改行)
\ r U + 000D キャリッジリターン[5](またはMac OS 9以前の改行)
\ t U + 0009 水平タブ[5]
\ v U + 000B 垂直タブ[5]
\ e U + 001B エスケープ文字[6]GCC[7] clangおよびtcc
\ u #### U + #### ####が4桁の16進数である16ビットUnicode文字[4]
\ U ######## U + ###### ########が8桁の16進数である32ビットUnicode文字(Unicode文字スペースは現在21ビット幅しかないため、最初の2桁の16進数は常にゼロになります)
\ u {######} U + ###### 21ビットUnicode文字。######は16進数の可変数です。
\バツ## U + 00 ## #が16進数である8ビット文字の指定[5]
\ ooo U + 0 ### oが8進数の8ビット文字仕様[5]
\ " U + 0022 二重引用符( ")[5]
\& Haskellで数値エスケープを区切るために使用される非文字[3]
\ ' U + 0027 一重引用符( ')[5]
\\ U + 005C バックスラッシュ(\)[5]
\? U + 003F 疑問符(?)[5]

注:リスト内のすべてのシーケンスがすべてのパーサーでサポートされているわけではなく、リストにない他のエスケープシーケンスが存在する可能性があります。

ネストされたエスケープ

あるプログラミング言語のコードが別のプログラミング言語に埋め込まれている場合、埋め込まれた文字列には複数レベルのエスケープが必要になる場合があります。これは、他の言語内の正規表現やSQLクエリ、またはシェルスクリプト内の他の言語で特に一般的です。この二重エスケープは、多くの場合、読み取りと作成が困難です。

ネストされた文字列の引用符が正しくないと、セキュリティの脆弱性が生じる可能性があります。SQLクエリのデータフィールドのように、信頼できないデータを使用する場合は、コードインジェクション攻撃を防ぐためにプリペアドステートメントを使用する必要があります。PHP 2から5.3には、(利便性とセキュリティのために)文字列を自動的にエスケープするマジッククォートと呼ばれる機能がありましたが、問題ためにバージョン5.4以降から削除されました。

生の文字列

いくつかの言語は、リテラルが言語固有の解釈なしで処理されることを指定する方法を提供します。これにより、エスケープの必要がなくなり、より読みやすい文字列が生成されます。

生の文字列は、一般的な文字をエスケープする必要がある場合、特にバックスラッシュ\が広く使用されている正規表現(文字列リテラルとしてネストされている)や、バックスラッシュがパス区切り文字として使用されているDOS / Windowsパスで特に役立ちます。バックスラッシュの多さは傾いた楊症候群として知られており、生の弦を使用することで減らすことができます。C#でエスケープされたパス名と生のパス名を比較します。

 "WindowsパスはC:\\ Foo \\ Bar \\ Baz \\" 
 @ "WindowsパスはC:\ Foo \ Bar \ Baz \"

これらを組み合わせると極端な例が発生します。UniformNamingConventionパスはで始まります。したがって、文字列と正規表現をエスケープする必要があるため\\、UNC名に一致するエスケープされた正規表現は8つの円記号で始まります。"\\\\\\\\"生の文字列を使用すると、C#の場合と同様に、これが4に減少します(正規表現でエスケープされます)@"\\\\"

XMLドキュメントでは、CDATAセクションを使用すると、XMLパーサーがドキュメント自体の構造の一部として解釈しようとせずに、&や<などの文字を使用できます。これは、リテラルテキストとスクリプトコードを含めるときに、ドキュメントを適切に形成するために役立ちます

<![CDATA [if(path!= null && depth <2){add(path); }]]>

複数行の文字列リテラル

多くの言語では、文字列リテラルには、複数の行にまたがるリテラルの改行を含めることができます。または、ほとんどの場合、改行をエスケープすることもできます\n例えば:

エコー 'foo 
bar'

echo -e "foo \ nbar"

どちらも有効なbashであり、以下を生成します。

foo
バー

文字通りの改行を許可する言語には、bash、Lua、Perl、PHP、R、およびTclが含まれます。他のいくつかの言語では、文字列リテラルに改行を含めることはできません。

複数行の文字列リテラルに関する2つの問題は、先頭と末尾の改行とインデントです。最初または最後の区切り文字が別々の行にある場合は、余分な改行がありますが、そうでない場合は、特に最初の行の文字列が読みにくくなります。最初の行は、他の行とは異なるインデントが付けられることがよくあります。さらに、先頭の空白が保持されるため、リテラルはインデントされていない必要があります。これにより、リテラルがインデントされたコード内で発生した場合、コードのフローが中断されます。

これらの問題の最も一般的な解決策は、ここではドキュメントスタイルの文字列リテラルです。正式に言えば、ヒアドキュメントは文字列リテラルではなく、ストリームリテラルまたはファイルリテラルです。これらはシェルスクリプトに由来し、リテラルを外部コマンドへの入力として提供できるようにします。開始区切り文字は任意の単語を指定できる<<END場所であり、終了区切り文字はそれ自体が1行にあり、コンテンツの境界として機能します。これは、文字からstdinをリダイレクトするためです。区切り文字は任意であるため、これらは区切り文字の衝突の問題も回避します。これらにより、バリアント構文を介して初期タブを削除することもできますENDEND<<<<-ENDただし、先頭のスペースは削除されません。それ以来、同じ構文が多くの言語、特にPerlの複数行文字列リテラルに採用されており、ヒアドキュメントとも呼ばれ、文字列でありリダイレクトを伴わないにもかかわらず、構文を保持します。他の文字列リテラルと同様に、これらは変数の補間など、異なる動作を指定する場合があります。

Pythonは、通常の文字列リテラルではリテラルの改行を許可しませんが、代わりに、トリプルクォートと呼ばれる複数行リテラル用に設計された特殊な形式の文字列を備えています。'''これらは、またはのいずれかで3倍の区切り文字を使用します"""これらのリテラルは、特にdocstringsと呼ばれるインラインドキュメントに使用されます

Tclは文字列のリテラル改行を許可し、複数行の文字列を支援する特別な構文はありませんが、区切り文字はそれ自体で行に配置でき、先頭と末尾の改行はを介して削除できstring trimstring mapインデントを削除するために使用できます。

文字列リテラルの連結

いくつかの言語は、文字列リテラルの連結を提供します。この場合、隣接する文字列リテラルは、コンパイル時に1つのリテラルに暗黙的に結合されます。これは、C、[8] [9] C ++、[10] D、[11] Ruby、[12]およびPython、[13]の機能であり、Cからコピーしたものです。[14]特に、この連結はコンパイル時に発生します。時間、字句解析中(最初のトークン化に続くフェーズとして)、実行時の文字列連結(通常は+演算子を使用)[15]と一定の折りたたみ中の連結の両方と対比されます、これはコンパイル時に発生しますが、後のフェーズ(フレーズ分析または「解析」の後)で発生します。C#、Java [16]、Perlなどのほとんどの言語は、暗黙的な文字列リテラルの連結をサポートしていません。代わりに、演算子などを使用した明示的な連結が必要です+(これは、DやPythonでも可能ですが、C / C ++では無効です–下記参照); この場合、連結はコンパイル時に定数畳み込みを介して発生するか、実行時に延期される可能性があります。

モチベーション

概念と用語が由来するCでは、2つの理由で文字列リテラルの連結が導入されました。[17]

  • インデントスキームを破壊する行の継続とは対照的に、長い文字列が適切なインデントで複数の行にまたがることを可能にするため。
  • マクロによる文字列リテラルの構築を可能にするため(stringizingを介して)。[18]

実際には、これにより、フレーズ分析や定数畳み込みを必要とせずに、コンパイルの初期段階(「翻訳」、特に字句解析の一部として)で文字列を連結できます。たとえば、有効なC / C ++は次のとおりです。

char * s = "hello、" "world" ;    
printf "hello、" "world" ); 

ただし、以下は無効です。

char * s = "hello、" + "world" ;     
printf "hello、" + "world" );  

これは、文字列リテラルの配列タイプ(C)または(C ++)であり、追加できないためです。これは他のほとんどの言語の制限ではありません。 char [n]const char [n]

これは、 Cプリプロセッサと組み合わせて使用​​する場合、特にマクロで前処理後に文字列を計算できるようにするために特に重要です。[14]簡単な例として:

char * file_and_message = __FILE__ ":メッセージ" ;    

(ファイルがacと呼ばれる場合)次のように展開されます:

char * file_and_message = "ac" ":メッセージ" ;    

次に連結され、次と同等になります。

char * file_and_message = "ac:メッセージ" ;   

一般的な使用例は、printfまたはscanf形式の文字列を作成する場合です。ここで、形式指定子はマクロによって指定されます。[19] [20]

より複雑な例では、(プリプロセッサによる)整数の文字列化を使用して、文字列リテラルのシーケンスに展開するマクロを定義します。このマクロは、ファイル名と行番号を持つ単一の文字列リテラルに連結されます。[21]

#define STRINGIFY(x)#x 
#define TOSTRING(x)STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__ LINE__)

C / C ++の構文要件を超えて、暗黙の連結は構文シュガーの形式であり、文字列リテラルを複数の行に分割するのが簡単になり、行の継続(バックスラッシュによる)の必要がなくなり、文字列の一部にコメントを追加できるようになります。たとえば、Pythonでは、次のように正規表現にコメントを付けることができます。[22]

コンパイル"[A-Za-z _]"        #文字またはアンダースコア
           "[A-Za-z0-9 _] *"    #文字、数字、またはアンダースコア
          

問題

定数畳み込みを実装する最新のコンパイラでは、暗黙的な文字列の連結は必要ありません。特に、文字列の垂直リストでは、次のように、意図しない連結によってコンマが省略されるため、見つけにくいエラーが発生します。

l  =  [ 'foo' 
     ' 
     bar''zork' ]

したがって、ほとんどの言語では使用されておらず、D [23]およびPythonからの非推奨が提案されています。[14]ただし、この機能を削除すると互換性が失われ、連結演算子に置き換えると、優先順位の問題が発生します。文字列のリテラル連結は、演算子の評価前の字句処理中に発生しますが、明示的な演算子による連結は、他の演算子と同時に発生します。したがって、優先順位が問題になり、目的の評価順序を確保するために括弧が必要になる可能性があります。

微妙な問題は、CとC ++では[24]異なるタイプの文字列リテラルがあり、これらの連結には実装定義の動作があり、潜在的なセキュリティリスクをもたらすことです。[25]

さまざまな種類の文字列

一部の言語は、動作が異なる複数の種類のリテラルを提供します。これは特に、生の文字列(エスケープなし)を示すため、または変数の補間を無効または有効にするために使用されますが、文字セットの区別など、他の用途もあります。ほとんどの場合、これは引用符を変更するか、接頭辞または接尾辞を追加することによって行われます。これは、16進数や長整数を示すなど、 整数リテラルの接頭辞と接尾辞に相当します。

最も古い例の1つはシェルスクリプトで、一重引用符は生の文字列または「リテラル文字列」を示し、二重引用符にはエスケープシーケンスと変数補間があります。

たとえば、Pythonでは、生の文字列の前にror R–と比較'C:\\Windows'r'C:\Windows'ます(ただし、Pythonの生の文字列を奇数の円記号で終わらせることはできません)。Python 2は、2種類の文字列も区別します。8ビットASCII( "bytes")文字列(デフォルト)は、明示的にabまたはBプレフィックスで示され、Unicode文字列はauまたはUプレフィックスで示されます。[26] Python 3では、文字列はデフォルトでUnicodeであり、バイトは別のbytesタイプであり、引用符で初期化する場合は、プレフィックスとして。を付ける必要がありますb

生の文字列に対するC#の表記は、@引用符と呼ばれます。

@ "C:\ Foo \ Bar \ Baz \"

これによりエスケープは無効になりますが、二重引用符が許可され、文字列内で引用符を表すことができます。

@ "私は言った、" "こんにちは" ""

C ++ 11では、生の文字列、Unicode文字列(UTF-8、UTF-16、およびUTF-32)、およびプレフィックスによって決定されるワイド文字列を使用できます。また、既存のC ++のリテラルも追加しますstring。これは、既存のCスタイルの文字列よりも一般的に優先されます。

Tclでは、中括弧で区切られた文字列はリテラルですが、引用符で区切られた文字列にはエスケープと補間があります。

Perlには多種多様な文字列があり、それらはより正式には演算子と見なされ、quoteおよびquote-like演算子として知られています。これらには、通常の構文(固定区切り文字)と、区切り文字を選択できる一般的な構文の両方が含まれます。これらには以下が含まれます:[27]

''   ""   ``   //   m //   qr //   s ///   y // / 
q {}   qq {}   qx {}   qw {}   m {}   qr {}   s {} {}   tr {} {}   y {} {}

REXXは、サフィックス文字を使用して、16進コードまたは2進コードを使用して文字またはストリングを指定します。例えば、

'20' x
「00100000」 b
「00100000」 b

すべてがスペース文字を生成し、関数呼び出しを回避しますX2C(20)

文字列補間

一部の言語では、文字列リテラルに、現在のコンテキストで(通常は実行時に)評価される変数または式を参照するプレースホルダーが含まれる場合があります。これは、可変補間、またはより一般的には文字列補間と呼ばれます。補間をサポートする言語は、通常、補間された文字列リテラルとそうでない文字列リテラルを区別します。たとえば、sh互換のUnixシェルでは(PerlおよびRubyと同様に)、二重引用符で囲まれた(quotation-delimited、 ")文字列は補間されますが、一重引用符で囲まれた(apostrophe-delimited、 ')文字列は補間されません。文字列」ですが、これはエスケープの意味で「生の文字列」とは異なります。たとえば、Pythonでは、接頭辞または接頭辞が付いた文字列にrRエスケープまたは補間がなく、通常の文字列(接頭辞なし)にはエスケープがありますが補間はありません。接頭辞が付いている、fまたはFエスケープと補間が ある文字列。

たとえば、次のPerlコード:

$ name      =  "ナンシー" ; 
$ greeting  =  "Hello World" ; 
印刷 「$ nameは人々の群衆に$ greetingを言った。」;

出力を生成します:

ナンシーは人々の群衆にハローワールドを言いました。

この場合、メタ文字文字($)(変数割り当てステートメントの印章と混同しないでください)は、変数の補間を示すと解釈され、文字通りに出力する必要がある場合は、エスケープが必要です。

printfこれは、次のような表記を使用して同じ出力を生成する関数 とは対照的です。

printf  "%sは人々の群衆に%sを言いました。"  $ name  $ greeting ;

ただし、補間は実行しません。はprintf形式の文字列%sのプレースホルダーですが、変数自体は文字列の外側にあります。

これは「生の」文字列とは対照的です。

印刷 '$ nameは$人々の群衆に挨拶すると言った。;

次のような出力を生成します。

$ nameは、人々の群衆に$ greetingと言いました。

ここで、$文字はメタ文字ではなく、プレーンテキスト以外の意味を持つとは解釈されません。

文字列リテラルへのソースコードの埋め込み

文字列リテラルを指定する際の柔軟性に欠ける言語では、他のプログラミングコードを生成するプログラミングコードを書くのが特に面倒になります。これは、生成言語が出力言語と同じまたは類似している場合に特に当てはまります。

例えば:

  • クワインを生産するためのコードを書く
  • Webテンプレート内から出力言語を生成する;
  • XSLTを使用してXSLTを生成するか、SQLを使用してより多くのSQLを生成します
  • Cまたは他の言語で記述されたドキュメント処理アプリケーション内から、印刷目的でドキュメントのPostScript表現を生成します。
  • シェーダーを書く

それにもかかわらず、一部の言語、特に区切り文字の衝突を回避するための複数のオプションをサポートする言語は、この種の自己相似出力を生成するように特によく適合されています。

他のコードを生成するコードとして文字列リテラルを使用すると、特に出力が信頼できないユーザー入力に少なくとも部分的に基づいている場合、セキュリティに悪影響を与える可能性があります。これは、悪意のあるユーザーがSQLインジェクション攻撃を仕掛ける などして、アプリケーションの操作を妨害するためにこのような弱点を利用できるWebベースのアプリケーションの場合に特に深刻です。

も参照してください

メモ

  1. ^ 混乱を減らすために、ここに示されている正規表現自体は引用またはエスケープされていません。

参考文献

  1. ^ 「Javaの紹介-MFC158G」文字列リテラル(または定数)は「匿名文字列」と呼ばれます
  2. ^ 「ANSIC文法(Lex)」liu.se。_ 2016年6月22日取得
  3. ^ a b "付録B.文字、文字列、およびエスケープ規則"realworldhaskell.org 2016年6月22日取得
  4. ^ a b "文字列"mozilla.org 2016年6月22日取得
  5. ^ a b c d e f g h i j k l m 「エスケープシーケンス(C)」microsoft.com 2016年6月22日取得
  6. ^ a b 「国際標準の理論的根拠-プログラミング言語-C」(PDF)5.10。2003年4月。pp。52、153–154、159。2016-06-06のオリジナルからアーカイブ(PDF)2010年10月17日取得
  7. ^ 「6.35定数の文字<ESC>」GCC 4.8.2マニュアル、2014年3月8日取得
  8. ^ C11ドラフト標準、 WG14 N1570委員会ドラフト— 2011年4月12日、5.1.1.2翻訳フェーズ、p。11:「6。隣接する文字列リテラルトークンが連結されます。」
  9. ^ C構文:文字列リテラルの連結
  10. ^ C ++ 11ドラフト標準、「作業ドラフト、プログラミング言語C ++の標準」(PDF) 、2.2翻訳のフェーズ[lex.phases]、p。17:「6。隣接する文字列リテラルトークンが連結されます。」および2.14.5文字列リテラル[lex.string]、注13、p。28–29:「翻訳フェーズ6(2.2)では、隣接する文字列リテラルが連結されます。」
  11. ^ Dプログラミング言語 字句解析、 "文字列リテラル": "隣接する文字列は〜演算子または単純な並置によって連結されます:"
  12. ^ ruby​​:Rubyプログラミング言語、Rubyプログラミング言語、2017-10-19、2017-10-19取得
  13. ^ Python言語リファレンス、2。字句解析、 2.4.2。文字列リテラルの連結:「複数の隣接する文字列リテラル(空白で区切られている)は、おそらく異なる引用規則を使用して許可され、それらの意味は連結と同じです。」
  14. ^ a b c Python-アイデア、「暗黙の文字列リテラルの連結は有害と見なされますか?」、Guido van Rossum、2013年5月10日
  15. ^ Python言語リファレンス、2。字句解析、 2.4.2。文字列リテラルの連結:「この機能は構文レベルで定義されていますが、コンパイル時に実装されることに注意してください。実行時に文字列式を連結するには、「+」演算子を使用する必要があります。」
  16. ^ "文字列(Java™チュートリアル> Java言語の学習>数字と文字列)"Docs.oracle.com2012-02-28 2016年6月22日取得
  17. ^ ANSICプログラミング言語の理論的根拠シリコンプレス。1990.p。 31ISBN 0-929306-07-43.1.4文字列リテラル: "バックスラッシュ-改行行の継続を使用して、長い文字列を複数の行にまたがって継続できますが、この方法では、文字列の継続を次の行の最初の位置から開始する必要があります。より柔軟なレイアウトを可能にし、一部を解決するには前処理の問題(§3.8.3を参照)では、委員会は文字列リテラルの連結を導入しました.2つの文字列リテラルを続けて貼り付けて(中央にヌル文字を含めずに)、1つの結合された文字列リテラルを作成します。このC言語への追加により、プログラマーは、バックスラッシュ-改行メカニズムを使用せずに文字列リテラルを物理行の終わりを超えて拡張し、それによってプログラムのインデントスキームを破棄します。連結は実行ではなく字句構造であるため、明示的な連結演算子は導入されませんでした。 -時間操作。「」
  18. ^ ANSICプログラミング言語の理論的根拠シリコンプレス。1990.p。 6566ISBN 0-929306-07-43.8.3.2#演算子: "#演算子は文字列化のために導入されました。これは#define展開でのみ使用できます。これにより、後続の仮パラメータ名が、実際の引数トークンを文字列化することによって形成された文字列リテラルに置き換えられます。シーケンス。文字列リテラルの連結(§3.1.4を参照)と組み合わせて、この演算子を使用すると、文字列内の識別子の置換と同じくらい効果的に文字列を作成できます。標準の例は、この機能を示しています。」
  19. ^ C / C ++ユーザージャーナル、第19巻、 p。50
  20. ^ 「python-文字列リテラルの連結を許可するのはなぜですか?」スタックオーバーフロー2016年6月22日取得
  21. ^ "LINE__ to string(stringify)using preprocessordirectives"Decompile.com2006-10-12 2016年6月22日取得
  22. ^ Python言語リファレンス、2。字句解析、 2.4.2。文字列リテラルの連結: "この機能を使用すると、必要なバックスラッシュの数を減らしたり、長い文字列を長い行に便利に分割したり、文字列の一部にコメントを追加したりできます。たとえば、次のようになります。
  23. ^ DLangの問題追跡システム–問題3827-隣接する文字列リテラルの暗黙的な連結に対して警告し、非推奨にします
  24. ^ C ++ 11ドラフト標準、「作業ドラフト、プログラミング言語C ++の標準」(PDF) 、2.14.5文字列リテラル[lex.string]、注13、p。28–29:「他の連結は、実装定義の動作で条件付きでサポートされます。」
  25. ^ 「アーカイブされたコピー」2014年7月14日にオリジナルからアーカイブされました2014年7月3日取得{{cite web}}:CS1 maint:タイトルとしてアーカイブされたコピー(リンク
  26. ^ 「2。字句解析— Python2.7.12rc1ドキュメント」python.org 2016年6月22日取得
  27. ^ "perlop--perldoc.perl.org"perl.org 2016年6月22日取得

外部リンク