言語別テンプレートリテラル・文字列補間の書き方|Python・Ruby・Swiftは実行して検証
文字列の中に変数や式を埋め込む書き方を、言語ごとにまとめます。JavaScriptではテンプレートリテラル、Pythonではf-string、Rubyなどでは文字列補間と呼ばれますが、やろうとしていることは同じです。
この記事は検証した範囲を明示します。当環境で実際に実行して出力を確認できたのは Python・Ruby・Swift の3言語です。残りの言語は公式ドキュメントの仕様にもとづいて書き、実行はしていません。どちらなのかは各節の冒頭に書きます。確認日は2026年9月28日です。
| 言語 | 検証 | バージョン |
|---|---|---|
| Python | 実行して確認 | Python 3.9.6 |
| Ruby | 実行して確認 | ruby 2.6.10 |
| Swift | 実行して確認 | Apple Swift 6.3.3 |
| JavaScript / C# / Kotlin / Rust / Go / Java / PHP | 公式仕様にもとづく(未実行) | — |
旧版にあった「ベンチマークテスト結果」の節は削除しました。出典も測定条件も示せない数値だったためです。代わりに、実行できた2言語で自分で測った数値を後半に載せています。
Python — f-string【実行して確認】
文字列の前に f を付けると、{} の中が式として評価されます。Python 3.6 で入りました。
name, age = '太郎', 25
print(f'こんにちは、{name}さん。{age}歳ですね。')
# こんにちは、太郎さん。25歳ですね。
print(f'{age * 2}') # 50 式が書ける
print(f'{3.14159:.2f}') # 3.14 小数点以下2桁
print(f'{1234567:,}') # 1,234,567 3桁区切り
print(f'{255:#x}') # 0xff 16進
print(f'{0.25:.1%}') # 25.0% パーセント
print(f'{name:>10}|') # 太郎| 右寄せ10文字
print(f'{name:^10}|') # 太郎 | 中央寄せ
print(f'{{中括弧そのもの}}') # {中括弧そのもの}
デバッグ記法(3.8以降)
= を付けると変数名と値を一緒に出せます。print デバッグがかなり楽になります。
print(f'{name=} {age=}')
# name='太郎' age=25
日付の書式もそのまま書ける
import datetime
print(f'{datetime.date(2026, 9, 28):%Y年%m月%d日}')
# 2026年09月28日
【実測】3.12より前のバージョンで引っかかる制限
Python 3.9.6 で実行して確認した制限です。いずれも Python 3.12(PEP 701)で解除されました。古い環境を使っている場合は今も引っかかります。
d = {'k': 'v'}
print(f'{d["k"]}') # OK … 外が ' 、中が " なら通る
print(f"{d["k"]}") # SyntaxError: f-string: unmatched '['
# 同じ種類のクォートは入れ子にできない(3.12で解禁)
print(f"{1 +
2}") # SyntaxError: EOL while scanning string literal
# 式の途中で改行できない(3.12で解禁)
対処は単純で、外側と内側でクォートの種類を変えるだけです。3.12以降は同じクォートでも通りますが、古い環境でも動かすコードなら分けておくのが安全です。
Ruby — 文字列補間【実行して確認】
#{} の中が評価されます。ダブルクォートでしか展開されません。ここがPythonと違う点です。
name, age = "太郎", 25
puts "こんにちは、#{name}さん。#{age}歳ですね。"
# こんにちは、太郎さん。25歳ですね。
puts "#{age * 2}" # 50
puts "#{'%.2f' % 3.14159}" # 3.14
puts "#{format('%d円', 1234)}" # 1234円
puts "#{name.upcase} #{[1,2,3].sum}" # 太郎 6
# シングルクォートでは展開されない
puts '#{name}' # #{name}
式の中に if を書ける
Rubyの補間は式を丸ごと入れられます。if も式なのでそのまま書けます。
puts "#{if age >= 20 then "成人" else "未成年" end}"
# 成人
ヒアドキュメントでも展開される
puts <<~HEREDOC
ヒアドキュメント
名前は #{name}
HEREDOC
# ヒアドキュメント
# 名前は 太郎
Swift — 文字列補間【実行して確認】
\( ) の中が評価されます。
let name = "太郎", age = 25
print("こんにちは、\(name)さん。\(age)歳ですね。")
// こんにちは、太郎さん。25歳ですね。
print("\(age * 2)") // 50
【実測】書式指定には import Foundation が必要
これは実行して初めて分かった落とし穴です。String(format:) は標準ライブラリではなく Foundation にあります。
// import を忘れると
let x = String(format: "%.2f", 3.14)
// error: no exact matches in call to initializer
import Foundation // ← これが必要
print("\(String(format: "%.2f", 3.14159))") // 3.14
オプショナルはそのまま埋め込まない
nil になりうる値をそのまま補間すると Optional("値") のように出ます。実行して確認した挙動です。
let opt: String? = nil
print("\(opt ?? "未設定")") // 未設定 ← nil合体演算子
print("\(String(describing: opt))") // nil ← 明示的に文字列化
let opt2: String? = "値"
print("\(opt2 as Any)") // Optional("値") ← そのまま出てしまう
表示用の文字列を作るときは ?? で既定値を与えるのが基本です。
複数行リテラルでも展開される
print("""
複数行リテラル
名前は \(name)
""")
その他の言語【公式仕様にもとづく・当環境では未実行】
以下は当環境に処理系がないため実行していません。各言語の公式ドキュメントに記載されている構文です。実際に書く前に手元で動かして確かめてください。
JavaScript — テンプレートリテラル
バッククォートで囲み ${ } で埋め込みます。ES2015で導入されました。そのまま複数行が書けるのが大きな利点です。
const name = "太郎", age = 25;
console.log(`こんにちは、${name}さん。${age}歳ですね。`);
console.log(`合計: ${1 + 2}`);
// 複数行がそのまま書ける
console.log(`1行目
2行目`);
タグ付きテンプレートリテラルという仕組みもあり、埋め込む値を関数で加工できます。HTMLエスケープやSQLの安全な組み立てに使われる形です。
function esc(strings, ...values) {
return strings.reduce((acc, s, i) =>
acc + s + (values[i] == null ? "" :
String(values[i]).replace(/[&<>"']/g, c =>
({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }))), "");
}
const input = '<script>alert(1)</script>';
console.log(esc`入力: ${input}`);
C# — 文字列補間
文字列の前に $ を付け { } で埋め込みます。C# 6 で導入。
var name = "太郎"; var age = 25;
Console.WriteLine($"こんにちは、{name}さん。{age}歳ですね。");
Console.WriteLine($"{3.14159:F2}"); // 書式指定
Console.WriteLine($"{(age >= 20 ? "成人" : "未成年")}");
Kotlin — 文字列テンプレート
$変数 で直接、式は ${ } で囲みます。
val name = "太郎"; val age = 25
println("こんにちは、${name}さん。${age}歳ですね。")
println("$name") // 単純な変数は波括弧を省略できる
println("${name.length}") // 式やプロパティは波括弧が必要
Rust — format! マクロ
Rustには文字列補間の構文はなく、マクロを使います。Rust 2021 以降は {name} のように変数名を直接書ける形も使えます。
let name = "太郎";
let age = 25;
let s = format!("こんにちは、{name}さん。{age}歳ですね。");
println!("{}", s);
println!("{:.2}", 3.14159); // 書式指定
println!("{0}と{1}と{0}", "A", "B"); // 位置指定
Go — fmt.Sprintf
Goにも補間構文はありません。fmt.Sprintf を使います。
name, age := "太郎", 25
s := fmt.Sprintf("こんにちは、%sさん。%d歳ですね。", name, age)
fmt.Println(s)
fmt.Printf("%.2f\n", 3.14159)
Java — String.format とテキストブロック
Javaにも補間構文はありません。String.format を使います。複数行は Java 15 で入ったテキストブロック(""")が使えますが、テキストブロック自体に変数展開の機能はありません。
String name = "太郎";
int age = 25;
System.out.println(String.format("こんにちは、%sさん。%d歳ですね。", name, age));
// テキストブロック(Java 15+)。展開はされないので formatted() を併用する
String s = """
名前: %s
年齢: %d
""".formatted(name, age);
PHP — ダブルクォート内の変数展開
$変数 がそのまま展開されます。配列やプロパティは {$...} で囲むのが安全です。
$name = "太郎"; $age = 25;
echo "こんにちは、{$name}さん。{$age}歳ですね。\n";
echo sprintf("%.2f\n", 3.14159);
// シングルクォートでは展開されない
echo 'こんにちは、$nameさん'; // こんにちは、$nameさん
言語別の書き方まとめ
| 言語 | 書き方 | 複数行 | 呼び名 |
|---|---|---|---|
| JavaScript | `${式}` |
できる | テンプレートリテラル |
| Python | f'{式}' |
''' で囲む |
f-string |
| Ruby | "#{式}" |
ヒアドキュメント | 文字列補間 |
| Swift | "\(式)" |
""" で囲む |
文字列補間 |
| C# | $"{式}" |
$"""(C# 11+) |
文字列補間 |
| Kotlin | "$変数" / "${式}" |
""" で囲む |
文字列テンプレート |
| PHP | "{$変数}" |
Heredoc | 変数展開 |
| Rust | format!("{name}") |
— | (マクロ) |
| Go | fmt.Sprintf("%s") |
— | (書式指定) |
| Java | String.format("%s") |
テキストブロック(展開なし) | (書式指定) |
大きく2つに分かれます。文字列の中に式を書ける言語(JS・Python・Ruby・Swift・C#・Kotlin・PHP)と、書式文字列と引数を分ける言語(Rust・Go・Java)です。後者は型チェックが効きやすいという利点があります。
性能|実行できた2言語で測った
「補間は遅いのか」を実際に測りました。結果はどちらの言語も補間が最速でした。
Python 3.9.6(各500万回)
| 書き方 | 合計 | 1回あたり |
|---|---|---|
f"{n}は{a}歳" |
0.486 秒 | 97 ns |
"%sは%d歳" % (n, a) |
0.553 秒 | 111 ns |
"{}は{}歳".format(n, a) |
0.719 秒 | 144 ns |
n + "は" + str(a) + "歳" |
0.774 秒 | 155 ns |
ruby 2.6.10(各300万回)
| 書き方 | 合計 | 1回あたり |
|---|---|---|
"#{n}は#{a}歳" |
0.455 秒 | 152 ns |
n + "は" + a.to_s + "歳" |
0.546 秒 | 182 ns |
format("%sは%d歳", n, a) |
0.798 秒 | 266 ns |
補間は読みやすさと速さを同時に取れます。「速度のために連結や format を使う」という選択には根拠がありません。ただしいずれも1回100〜300ナノ秒で、数万回程度なら合計は数ミリ秒です。普通のコードでは速度を理由に書き方を選ぶ必要はありません。読みやすさで決めてください。
【最重要】SQLとHTMLには使ってはいけない
この記事でいちばん伝えたい点です。補間は便利ですが、SQL文とHTMLの組み立てに使うと脆弱性になります。実際に動かして確認しました。
import sqlite3
con = sqlite3.connect(':memory:')
con.execute('CREATE TABLE users(name TEXT, admin INT)')
con.execute("INSERT INTO users VALUES ('太郎', 0)")
evil = "' OR 1=1 --"
# やってはいけない書き方
bad = f"SELECT * FROM users WHERE name = '{evil}'"
print(bad)
# SELECT * FROM users WHERE name = '' OR 1=1 --'
print(con.execute(bad).fetchall())
# [('太郎', 0)] ← 条件が無効化され、全件返ってきた
# 正しい書き方(プレースホルダ)
print(con.execute('SELECT * FROM users WHERE name = ?', (evil,)).fetchall())
# [] ← 0件。文字列として正しく比較された
上の出力は実際の実行結果です。' OR 1=1 -- という入力で WHERE 句が無効化され、本来1件も返らないはずのクエリが全件を返しました。
対策はどの言語でも同じです。値を文字列に埋め込むのではなく、プレースホルダ(? や $1)でライブラリに渡します。ライブラリ側が型に応じたエスケープをします。
- SQL|文字列を組み立てず、プレースホルダを使う
- HTML|テンプレートエンジンの自動エスケープを使う。手で組むならエスケープ関数を必ず通す
- シェルコマンド|文字列にせず、引数を配列で渡す
- ログ|利用者の入力をそのまま補間すると、改行を混ぜて偽のログ行を作られる
「自分が書く値だから安全」という判断は危険です。今は固定値でも、後から変数に差し替えられます。SQLとHTMLでは最初からプレースホルダとエスケープを使う癖をつけてください。
使い分けの指針
- 基本は補間を使う|読みやすく、測った範囲では最速
- SQL・HTML・シェルには使わない|専用の安全な手段を使う
- 同じ文を何度も組み立てるなら書式文字列を定数にする|翻訳(多言語化)が必要な場面では、文と値を分けておくほうが扱いやすい
- 式を長く書きすぎない|補間の中に複雑な三項演算子を詰めると読めなくなる。手前で変数にする
まとめ
- 呼び名は違うがやることは同じ。JSはテンプレートリテラル、Pythonはf-string、他は文字列補間
- 式を埋め込める言語(JS・Python・Ruby・Swift・C#・Kotlin・PHP)と書式文字列を使う言語(Rust・Go・Java)に分かれる
- Pythonの同じクォートの入れ子と式中の改行は3.12で解禁。それ以前では SyntaxError(実測)
- Swiftの
String(format:)はimport Foundationが必要(実測) - Swiftでオプショナルをそのまま補間すると
Optional("値")になる(実測) - 性能は補間が最速。Python 97ns、Ruby 152ns(実測)。普通のコードでは気にしなくてよい
- SQLとHTMLには使わない。プレースホルダとエスケープを使う
文字列の組み立ては、どの言語でも最初に覚える部分です。テックジムでは東京・永田町の東京本校でゼロからはじめるPython入門講座(無料・対面・毎週開催)を開催しています。参加費はかかりません。
あわせて読みたい
- Pythonのformat()の使い方|f-stringとの書き分け
- SQLインジェクション対策完全ガイド|なぜ文字列を組み立ててはいけないのか
- Pythonエラー一覧|SyntaxErrorの読み方
- 変数名・関数名の付け方ルール|埋め込む値に良い名前を付ける
- 逆クォート(バッククォート)とは?|JavaScriptのテンプレートリテラルで使う記号「`」の入力方法と、ほかの言語での意味
掲載したコードのうちPython・Ruby・Swiftの出力とエラーメッセージ、および性能の数値は、2026年9月28日に当環境で実行して得たものです(Python 3.9.6 / ruby 2.6.10 / Apple Swift 6.3.3)。JavaScript・C#・Kotlin・Rust・Go・Java・PHP のコードは実行していません。各言語の公式ドキュメントにもとづく記述です。バージョンによって仕様が変わるため、使う前に手元で確認してください。





