文字列補間
コンピュータプログラミングにおいて、文字列補間(または変数補間、変数置換、変数拡張)とは、1つ以上のプレースホルダーを含む文字列リテラルを評価し、プレースホルダーを対応する値に置き換えた結果を生成するプロセスです。これは単純なテンプレート処理[1]の一種であり、正式には準引用符(または論理置換解釈)の一種です。プレースホルダーは変数名、あるいは一部の言語では任意の式であり、いずれの場合も現在のコンテキストで評価されます。
文字列補間は、文字列連結による文字列構築の代替手段です。文字列連結では、引用符で囲んだり外したりを繰り返す必要があります。[2]また、 printf形式の文字列に代入すると、変数が実際に使用される場所から遠く離れてしまいます。Rubyでの以下の例を考えてみましょう。
apples = 4 puts "私は#{ apples }個のリンゴを持っています。" # 文字列補間puts "私は " + String ( apples ) + " 個のリンゴを持っています。" # 文字列連結puts "私は %d 個のリンゴを持っています。" % apples # 書式文字列 通常、2 種類のリテラル式が提供されます。1 つは補間が有効で、もう 1 つは有効ではありません。補間されていない文字列はエスケープ シーケンスを使用することがあり、その場合はraw 文字列と呼ばれますが、それ以外の場合にはこれは別個であり、raw 文字列、補間されていない (ただしエスケープされた) 文字列、補間された (およびエスケープされた) 文字列の 3 つのクラスが生成されます。たとえば、Unix シェルでは、一重引用符で囲まれた文字列は raw 文字列で、二重引用符で囲まれた文字列は補間されています。プレースホルダは通常、裸の記号または名前付き記号(通常$は または%) (例:$applesまたは)、あるいは%apples中括弧付き(例: ) {apples}(場合によっては両方${apples}) で表されます。場合によっては、追加の書式指定子 (printf など) (例: ) を使用でき{apples:3}、場合によっては書式指定子自体が補間されます (例: ) {apples:width}。文字列の展開は通常、実行時に行われます。
文字列補間のサポートは言語によって大きく異なります。一部の言語では文字列補間が提供されておらず、代わりに連結、単純な書式設定関数、またはテンプレートライブラリが使用されています。文字列補間は、Apache Groovy、Julia、Kotlin、Perl、PHP、Python、Ruby、Scala、Swift 、 Tcl、そしてほとんどのUnixシェルなど、データの文字列表現を多用する多くのプログラミング言語で一般的に使用されています。
アルゴリズム
変数補間のための変数拡張アルゴリズムには主に2つの種類がある: [3]
- プレースホルダの置換と展開:検索と置換操作によって、元の文字列から新しい文字列を作成します。変数参照(プレースホルダ)を検索し、その変数値に置き換えます。このアルゴリズムはキャッシュ戦略を提供しません。
- 文字列の分割と結合:文字列を配列に分割し、対応する値の配列と結合し、連結によって項目を結合します。分割された文字列はキャッシュして再利用できます。
セキュリティ問題
文字列の連結と同様に、文字列の補間はセキュリティ上の問題を引き起こす可能性があります。ユーザー入力データが不適切にエスケープまたはフィルタリングされると、システムはSQLインジェクション、スクリプトインジェクション、XML外部エンティティ(XXE)インジェクション、クロスサイトスクリプティング(XSS)攻撃にさらされることになります。[4]
SQL インジェクションの例:
クエリ = " "SELECT x, y, z FROM Table WHERE id='$id'が" "$idに置き換えられた場合、このクエリを実行すると 内のすべてのデータが消去されます。'; DELETE FROM Table; SELECT * FROM Table WHERE id='Table
例
ABAP
DATA (リンゴ) = 4 . WRITE |私は{リンゴ}個を持っています|。 出力は次のようになります。
私はリンゴを4個持っていますバッシュ
apples = 4 echo "私は$apples個のリンゴを持っています" # またはecho "私は${ apples }個のリンゴを持っています" 出力は次のようになります。
私はリンゴを4個持っていますブー
apples = 4 print ( "私は$(apples)個のリンゴを持っています" ) # またはprint ( "私は{0}個のリンゴを持っています" % apples ) 出力は次のようになります。
私はリンゴを4個持っていますC
C には補間文字列はありませんが、sprintf()from を使用して近似することができます<stdio.h>。
#include <stdio.h> #BUFFER_SIZE 100 を定義しますint main () { char sentence [ BUFFER_SIZE ]; int age = 20 ; float height = 5.9 ; char name [] = "Alice" ; sprintf ( sentence , "私の名前は %s で、年齢は %d 歳、身長は %.1f フィートです。" , name , age , height ); printf ( sentence ); // 出力: // 私の名前は Alice で、年齢は 20 歳、身長は 5.9 フィートです。} C++
C++ には補間文字列は存在しませんが、関数std::formatとstd::print関数を使用して近似することができます。
stdをインポートします。 std :: stringを使用します。 int main () { intリンゴ= 4 ; intバナナ= 3 ; std :: println ( "I have {} apples" , apples ); // 書式指定子std :: println ( "I have {0} fruits, of which there are {1} apples and {2} bananas" , apples + bananas , apples , bananas ); // 位置を明示的に指定 // std::format() を使用します: string name = "John Doe" ; int age = 20 ; string greeting = std :: format ( "こんにちは、{}さん!あなたは {} 歳です。" , name , age ); } 補間文字列は、 {fmt}ライブラリに基づいてC++に組み込むことが提案されています。[5]
C#
パブリッククラスExample { static void Main ( string [] args ) { int apples = 4 ; int bananas = 3 ; Console.WriteLine ( $"私は{apples}個のリンゴを持っています" ); Console.WriteLine ( $ "私は{apples + bananas}個の果物を持っています" ) ; } } [6]
出力は次のようになります。
私はリンゴを4個持っています。果物は7個あります。これは を使用して行うこともできますString.Format()。
システムを使用します。 パブリッククラスExample { static void Main ( string [] args ) { int apples = 4 ; int bananas = 3 ; Console . WriteLine ( String . Format ( "リンゴが {0} 個、バナナが {1} 個あります。" ,リンゴ、バナナ)); } } ColdFusion マークアップ言語
ColdFusion マークアップ言語(CFML) スクリプト構文:
apples = 4 ; writeOutput ( "私は#apples#個のリンゴを持っています" );タグ構文:
<cfset apples = 4 > <cfoutput>私は#個のリンゴを持っています#個のリンゴ</cfoutput>出力は次のようになります。
私はリンゴを4個持っています
コーヒースクリプト
apples = 4コンソール. log "私は#{ apples }個持っています" 出力は次のようになります。
私はリンゴを4個持っていますダーツ
int apples = 4 , bananas = 3 ; print ( '私は$個の applesを持っています。' ); print ( '私は${ apples + bananas }個の果物を持っています。' ); 出力は次のようになります。
リンゴが4個あります。果物が7個あります。行く
文字列補間の提案はいくつかあったが(却下された)、[7] [8] [9] 2025年現在、[アップデート]Goには補間された文字列はない。
ただし、 を使用して近似することはできますfmt.Sprintf()。
「fmt」をインポート func main () { // message は文字列型ですmessage := fmt . Sprintf ( "私の名前は%sで、年齢は%d歳です。" , "John Doe" , 20 ) fmt . Println ( message ) } グルーヴィー
Groovyでは、補間文字列はGStringと呼ばれます。[10]
def quality = "superhero" final age = 52 def sentence = "開発者が${age <= 42 ? 'young' : 'seasoned'}の場合、その開発者は$qualityです" println sentence 出力は次のようになります。
経験豊富な開発者はスーパーヒーローだハックス
var apples = 4 ; var bananas = 3 ; trace ( '私は$個のリンゴを持っています。' ); trace ( '私は${個のリンゴ+バナナ}個の果物を持っています。' ); 出力は次のようになる: [11]
リンゴが4個あります。果物が7個あります。ジャワ
Java では、Java 21 および Java 22 でプレビュー機能として文字列の補間が可能になりました。java.lang.StringTemplate の定数 STR を直接使用できました。
enum Stage { TEST 、QA 、PRODUCTION } レコード デプロイ( UUIDイメージ、ステージステージ) {} public class Example { public static void main ( String [] args ) { Deploy deploy = new Deploy ( UUID . randomUUID (), Stage . TEST ) STR . "ステージ \{deploy.stage()} に \{deploy.image()} をインストールしています..." Deploy deploy = new Deploy ( UUID . randomUUID (), Stage . PRODUCTION ) STR . "ステージ \{deploy.stage()} に \{deploy.image()} をインストールしています..." } } これらは設計上の問題によりJava 23で削除されました。[12]
それ以外の場合は、補間された文字列をString.format()メソッドを使用して近似することができます。
パブリッククラスExample { public static void main ( String [] args ) { int apples = 3 ; int bananas = 4 ; String sentence = String.format ( "私は%d個の果物を持っています。そのうち%d個はリンゴで%d個はバナナです。" 、リンゴ+バナナ、リンゴ、バナナ) ; System.out.println ( sentence ) ; String name = "John Doe" ; int age = 20 ; System . out . printf ( "私の名前は %s で、 %d 歳です。" , name , age ); } } JavaScript/TypeScript
JavaScriptとTypeScriptは、 ECMAScript 2015(ES6)標準以降、バッククォートを使用した文字列補間をサポートしています``。この機能はテンプレートリテラルと呼ばれます。[13]以下に例を示します。
const apples : number = 4 ; const bananas : number = 3 ; console . log ( ` ${ apples }個のリンゴがあります` ); console . log ( ` ${ apples + bananas }個の果物があります` ); 出力は次のようになります。
私はリンゴを4個持っています。果物は7個あります。テンプレートリテラルは複数行の文字列にも使用できます。
console . log ( `これはテキストの最初の行です。これはテキストの 2 行目です。` );出力は次のようになります。
これはテキストの最初の行です。これはテキストの2行目です。ジュリア
リンゴ= 4バナナ= 3 print ( "リンゴは$apples個、バナナは $bananas個あります。合計で果物は$ (リンゴ+バナナ)個です。" ) 出力は次のようになります。
リンゴが 4 個、バナナが 3 本あるので、果物は合計 7 個になります。コトリン
fun main () { val quality : String = "superhero" val apples : Int = 4 val bananas : Int = 3 val sentence : String = "開発者は$ qualityです。私は${ apples + bananas }個の果物を持っています" println ( sentence ) } 出力は次のようになります。
開発者はスーパーヒーローです。果物が7つありますネメルル
def apples = 4 ; def bananas = 3 ; Console . WriteLine ( $ "私は $apples 個のリンゴを持っています。" ); Console . WriteLine ( $ "私は $(apples + bananas) 個の果物を持っています。" ); また、次のような高度な書式設定機能もサポートしています。
def fruit = [ "apple" , "banana" ]; Console . WriteLine ( $ < #I have ..$(fruit; "\n"; f => f + "s")#>); 出力は次のようになります。
リンゴバナナニム
Nimはstrutilsモジュールを介して文字列補間を提供します。PythonのF文字列に着想を得たフォーマット済み文字列リテラルはstrformatモジュールを介して提供されます。strformatマクロはフォーマット文字列が整形式かつ適切に型付けされていることを検証し、コンパイル時にNimのソースコードに展開されます。
import strutils , strformat var apples = 4 var bananas = 3 echo "私は$1 個のリンゴを持っています" . format ( apples ) echo fmt"私は {apples} 個のリンゴを持っています" echo fmt"私は {apples + bananas} 個の果物を持っています" # 複数行のエコー形式" " "私は{リンゴ}個リンゴを持っています" "" # フォーマットをデバッグするecho fmt"I have {apples=} apples" # カスタム openChar および closeChar 文字echo fmt ( "I have (apples) {apples}" , '(' , ')' ) # フォーマットされた文字列リテラル内のバックスラッシュecho fmt" "" { " yep \ nope" } "" " 出力は次のようになります。
私はリンゴを 4 個持っています私はリンゴを 4 個持っています私は果物を 7 個持っています私はリンゴを4 個持っています 私はリンゴを 4 個持っています私にはリンゴが 4 個ありますはい、開けてくださいニックス
let numberOfApples = "4" ; in "私は${ numberOfApples }個のリンゴを持っています"出力は次のようになります。
私はリンゴを4個持っていますパラセール
const Apples := 4 const Bananas := 3 Println ( "私は `(Apples) 個のリンゴを持っています。\n" ) Println ( "私は `(Apples+Bananas) 個の果物を持っています。\n" )出力は次のようになります。
リンゴが4個あります。果物が7個あります。パール
my $apples = 4 ; my $bananas = 3 ; print "I have $apples apples.\n" ; print "I have @{[$apples+$bananas]} fruit.\n" ; # Perl 配列 (@) 補間を使用します。 出力は次のようになります。
リンゴが4個あります。果物が7個あります。PHP
<?php $apples = 5 ; $bananas = 3 ; echo "リンゴが$apples 個、バナナが$bananas個あります。\n " ; echo "リンゴが{ $apples }個、バナナが{ $bananas }本あります。" ;出力は次のようになります。
リンゴが5個とバナナが3本あります。私はリンゴが5個とバナナが3本持っています。パイソン
Pythonはバージョン3.6以降、「フォーマット文字列リテラル」または「f文字列」と呼ばれる文字列補間をサポートしています。[14] [15] [16]fこのようなリテラルは、引用符の前にorで始まりF、プレースホルダーとして中括弧を使用します。
num_apples : int = 4 num_bananas : int = 3 print ( f 'リンゴは{ num_apples }個、バナナは{ num_bananas }本あります' )出力は次のようになります。
リンゴが4個とバナナが3本ありますルビー/クリスタル
apples = 4 puts "I have #{ apples } apples" # 比較のための書式文字列の適用: puts "I have %s apples" % apples puts "I have %{a} apples" % { a : apples } 出力は次のようになります。
私はリンゴを4個持っていますさび
Rustには一般的な文字列補間機能はありませんが、2022年1月13日にリリースされたバージョン1.58.0で導入された「フォーマット文字列内のキャプチャされた識別子」と呼ばれるマクロを介して同様の機能を提供します。[17]
Rustはstd::fmtモジュールを介してフォーマット機能を提供します。このモジュールは、format!、write!、print!といった様々なマクロを介してインターフェースされます。これらのマクロはコンパイル時にRustのソースコードに変換され、各引数はフォーマッタと連携します。フォーマッタは、位置パラメータ、名前付きパラメータ、引数の型、様々なフォーマット特性の定義、環境からの識別子の取得をサポートしています。
fn main () { let ( apples , bananas ): ( i32 , i32 ) = ( 4 , 3 ); // println! はフォーマット時に識別子をキャプチャします。文字列自体は Rust によって補間されません。println! ( "There are {apples} apples and {bananas} bananas." ); // あるいは、format!() を使用します: let sentence : String = format! ( "There are {0} apples and {1} bananas." , apples , bananas ); println! ( sentence ); } 出力は次のようになります。
リンゴが4個、バナナが3本あります。スカラ
Scala 2.10以降では、文字列リテラルを任意に処理するための汎用的な機能が提供されており、標準の文字列補間器sとf文字列補間器を使用した文字列補間がサポートされています。また、カスタム補間器を作成したり、標準の補間器をオーバーライドしたりすることも可能です。
fインターポレータは、埋め込まれた式を含む書式文字列をString.formatの呼び出しとして書き換えるコンパイラマクロです。このマクロは、書式文字列が整形式かつ適切に型付けされているかどうかを検証します。
標準的な補間器
Scala 2.10以降の文字列補間機能により、処理済みの文字列リテラルに変数参照を直接埋め込むことができます。以下に例を示します。
val apples = 4 val bananas = 3 // Scala 2.10 より前printf ( "I have %d apples\n" , apples ) println ( "I have %d apples" format apples ) // Scala 2.10+ println ( s"I have $ apples apples" ) println ( s"I have ${ apples + bananas } fruits" ) println ( f"I have $ apples %d apples" ) 出力は次のようになります。
私はリンゴを4個持っていますシター(文字)
Sciter では、名前が $ で始まる関数はすべて補間関数として扱われるため、補間はカスタマイズ可能で、コンテキストに依存します。
varリンゴ= 4 varバナナ= 3 var domElement = ...; domElement . $content ( < p >私は{リンゴ}個を持っています< /p>); domElement . $append ( < p >私は{リンゴ+バナナ}個を持っています< /p>); どこ
domElement . $content ( < p >私は{リンゴ}個 のリンゴを持っています< /p>); 次のようにコンパイルされます:
domElement . html = "<p>私は " + apples . toHtmlString () + " 個のリンゴを持っています</p>" ; スノーボル
リンゴ = 4 ; バナナ = 3 出力 = "私は " リンゴ " 個持っています。 出力 = "私は " (リンゴ + バナナ) " 個持っています。"出力は次のようになります。
リンゴが4個あります。果物が7個あります。迅速
Swiftでは、定数、変数、リテラル、式の値を文字列リテラル内に含めることで、これらを組み合わせて新しい文字列値を作成できます。[18]文字列リテラルに挿入される各項目は、バックスラッシュを先頭に付けた括弧で囲まれます。
let apples = 4 print ( "私は\ (apples) 個のリンゴを持っています" ) 出力は次のようになります。
私はリンゴを4個持っていますTcl
ツール コマンド言語では、引用符で区切られたすべての文字列での文字列補間が常にサポートされています。
set apples 4は「$apples 個のリンゴがあります。」と入力します。 出力は次のようになります。
私はリンゴを4個持っています。値を単に置き換えるのではなく、実際にフォーマットするために、フォーマット機能があります。
set apples 4 puts [ format "リンゴが%d個あります。" $apples ] タイプスクリプト
TypeScriptバージョン 1.4 以降、バッククォートを使用した文字列補間がサポートされています``。以下に例を示します。
var apples : number = 4 ; console.log ( ` ${ apples }個のリンゴがあります`); 出力は次のようになります。
私はリンゴを4個持っていますこのconsole.log関数は関数として使用できますprintf。上記の例は次のように書き直すことができます。
var apples : number = 4 ; console . log ( "リンゴが %d 個あります" , apples ); 出力は同じままです。
ビジュアルベーシック.NET
Visual Basic 14以降では、Visual Basicで文字列の補間がサポートされています。[19]
name = " Tom" Console.WriteLine ( $ "こんにちは、{name}" ) 出力は次のようになります。
こんにちは、トム参照
注記
- ^ 「テンプレート エンジンでの厳密なモデルとビューの分離の強制」、T. Parr (2004)、WWW2004 カンファレンス。
- ^ 「Perlにおける補間」。2024年12月12日。
これは、「.」連結演算子を繰り返し使用するよりもはるかに簡潔です。
- ^ 「smallest-template-system/Simplest algorithms」、プレースホルダー テンプレート システムのオンライン チュートリアル。
- ^ 「Secure String Interpolation」。google -caja.googlecode.com。2012年10月19日時点のオリジナルよりアーカイブ。
- ^ ベングト・グスタフソン、ヴィクトル・ズヴェロヴィッチ (2024 年 10 月 14 日)。 「文字列補間 - p3412r0」(PDF)。open-std.org。 WG21。
- ^ 「文字列 - C#プログラミングガイド」。2024年3月15日。
- ^ 「提案: Go 2: 文字列補間 #34174」。GitHub。
- ^ 「提案: Go 2: 文字列補間を評価して文字列と式のリストにする #50554」。GitHub。
- ^ "proposal: spec: add simple string interpolation similar to Swift · Issue #57616 · golang/go". GitHub . 2025年5月19日閲覧。
- ^ 「Apache Groovyプログラミング言語 - 構文」. groovy-lang.org . 2021年6月20日閲覧。
- ^ 「Haxe - マニュアル - 文字列補間」。Haxe - クロスプラットフォームツールキット。 2017年9月12日閲覧。
- ^ 「JDK における重要な変更点」。
- ^ 「テンプレートリテラル(テンプレート文字列) - JavaScript | MDN」。2024年5月31日。
- ^ 「Python チュートリアル: 7.1.1. フォーマットされた文字列リテラル」。
- ^ 「Python 言語リファレンス: 2.4.3. フォーマットされた文字列リテラル」。
- ^ 「PEP 498 -- リテラル文字列の補間」。
- ^ 「Rust 1.58.0 の発表: フォーマット文字列で識別子をキャプチャ」2022年1月13日。
- ^ 「文字列と文字 — Swiftプログラミング言語(Swift 5.5)」. docs.swift.org . 2021年6月20日閲覧。
- ^ KathleenDollard. 「補間文字列 - Visual Basic」. docs.microsoft.com . 2021年6月20日閲覧。