文字列補間

プログラミングにおいて、**文字列補間**（もじれつほかん、）とは、内に埋め込まれたプレースホルダーを実行時に評価し、そのプレースホルダーを対応する値に置き換える処理である。**変数補間** （へんすうほかん、）、**変数置換**（へんすうちかん、）、**変数展開**（へんすうてんかい、）ともいう。この処理は、単純なテンプレートエンジンであり、正式な用語で言えばの一形態である。文字列補間は、文字列連結よりも簡単でより直観的に文字列のフォーマットを規定できる。

文字列補間は、データの文字列表現を多用する多くのプログラミング言語（C言語、Perl、PHP、Python、Ruby、Groovy、Scala、Swiftなど、および多くのUnixシェル）で使用できる。

文字列リテラルの表現には、文字列補間が使えるものと、使えないもの（raw文字列）がある。プレースホルダーは、無名もしくは名前のついたで示される。一般的には`$`や`%`が使用され、名前つきの場合は`$placeholder`や`%123`のようになる。文字列の補間はに行われる。

## 変種
いくつかの言語は文字列補間に対応していない。例えばC言語のprintf関数では、第1引数が書式化文字列であり、第2引数以降に書式化文字列内のプレースホルダーを置き換える定数・変数や式が置かれる。

Rubyでは"`[[番号記号|#]]`"を補間のための記号として使用するが、変数だけでなくどんな式でも補間できる。他の言語では、printfのような特別なフォーマット用の関数でより進んだ補間法に対応しているものもある。その場合、第1引数（フォーマット）で第2引数以降が代えられるパターンを指定する。

## アルゴリズム
文字列補間のための変数を展開するアルゴリズムには、主に2つの方法がある

# プレースホルダーの置換と展開 (*Replace and expand placeholders*) : オリジナルの文字列を元にして、検索置換 (find-replace) 演算によって新しい文字列を作成する。プレイスホルダーを見つけたら、それを変数の値に置き換える。このアルゴリズムは、キャッシュが使用できない。
# 文字列の分割と結合 (*Split and join string*) : 文字列を配列に分割する。そして、それを対応する値の配列に合併し、最後に、全ての配列を結合する。分割した文字列は、再理用のためにキャッシュしておくことができる。

## セキュリティ上の問題
文字列連結と同様、文字列補間はセキュリティ上の問題を招く可能性がある。プログラマがきちんとユーザー入力データをエスケープするかフィルターに通すかしないならば、システムはSQLインジェクション、スクリプトインジェクション、XML外部エンティティインジェクション (XXE)、クロスサイトスクリプティング (XSS) などの攻撃にさらされることになる。

以下は、SQLインジェクションを引き起こす文字列補間の例である。
 query = " "
ここで、*<code>$id</code>*が*"<code>'; </code>"*に補間された場合、このクエリを実行するとテーブルの全てのデータが削除されてしまう。

## 例
以下のPerlのコードは、PHPでも同じように動作する。

```perl
$name = "Alice";
print "${name} said Hello World to the crowd of people.";
```

このコードは、`Alice said Hello World to the crowd of people.`と出力する。

### [[Boo (プログラミング言語)|Boo]]

```boo
apples = 4
print("I have $(apples) apples")
# または
print("I have {0} apples" % apples)
```

上記のコードは以下のように出力する。

```text
I have 4 apples
```


### [[C Sharp|C#.NET]]

```csharp
var apples = 4;
// Before C# 6.0
System.Console.WriteLine(String.Format("I have {0} apples", apples));
// Before C# 6.0 WriteLineメソッド自体が書式指定に対応しているため、簡潔にこう書ける。
System.Console.WriteLine("I have {0} apples", apples);
// C# 6.0
System.Console.WriteLine($"I have {apples} apples");
```


上記のコードは以下のように出力する。

```text
I have 4 apples
```


### [[ColdFusion Markup Language|CFML]]
Script syntax:

```cfc
apples = 4;
writeOutput("I have #apples# apples");
```


Tag syntax:

```cfm
<cfset apples = 4>
<cfoutput>I have #apples# apples</cfoutput>
```


上記のコードは以下のように出力する。
 

### [[CoffeeScript]]

```coffeescript
apples = 4
console.log "I have #{apples} apples"
```

上記のコードは以下のように出力する。

```text
I have 4 apples
```


### [[Dart]]

```ecmascript
int apples = 4, bananas = 3;
print('I have $apples apples.');
print('I have ${apples+bananas} fruit.');
```

上記のコードは以下のように出力する。

```text
I have 4 apples.
I have 7 fruit.
```


### [[Groovy]]

```groovy
def quality = 'superhero'
def sentence = "A developer is a ${quality}"
print sentence
```

上記のコードは以下のように出力する。

```text
A developer is a superhero
```


### [[Haxe]]

```haxe
var apples = 4;
var bananas = 3;
trace('I have $apples apples.');
trace('I have ${apples+bananas} fruit.');
```

上記のコードは以下のように出力する。

```text
I have 4 apples.
I have 7 fruit.
```


### [[Nemerle]]

```boo
def apples = 4;
def bananas = 3;
Console.WriteLine($"I have $apples apples.");
Console.WriteLine($"I have $(apples + bananas) fruit.");
```

上記のコードは以下のようにも書ける。

```boo
def fruit = ["apple", "banana"];
Console.WriteLine($<#I have ..$(fruit; "\n"; f => f + "s")#>);
```

上記のコードは以下のように出力する。

```text
apples
bananas
```


### [[Perl]]

```perl
my $apples = 4;
my $bananas = 3;
print "I have $apples apples.\n";
print "I have @{[$apples+$bananas]} fruit.\n";  # Uses the Perl array (@) interpolation.
```

上記のコードは以下のように出力する。

```text
I have 4 apples.
I have 7 fruit.
```


### [[PHP (プログラミング言語)|PHP]]

```php
<?php
class foo {
    var $foo;
    var $bar;
    function foo() {
        $this->foo = 'Foo';
        $this->bar = array('Bar1', 'Bar2', 'Bar3');
    }
}
$foo = new foo();
$name = 'Jason';
echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>
```
上記のコードは以下のように出力する。

```text
My name is "Jason". I am printing some Foo.
Now, I am printing some Bar2.
This should print a capital 'A': A
```


### [[Python]]

```python
# in Python 2
apples = 4
print "I have %d apples" % apples
print "I have %(apples)d apples" % locals()
# or in Python 2.6
print "I have {} apples".format(apples)
print "I have {a} apples".format(a=apples)
# or in Python 3
print("I have {apples} apples".format(**locals()))
# or with Python 3.6
print(f"I have {apples} apples")
```
  
上記のコードは以下のように出力する。

```text
I have 4 apples
```


### [[Ruby]]

```ruby
apples = 4
puts "I have #{apples} apples"
# or
puts "I have %s apples" % apples
# or
puts "I have %{a} apples" % {a: apples}
```


上記のコードは以下のように出力する。

```text
I have 4 apples
```


### [[Scala]]
Scala 2.10以降には、s, f, rawの3つの文字列補間子が実装されている。

f補間子はString.formatを呼び出すための組み込み表現で、書式付き文字列を書き直すコンパイラ・マクロである。


```scala
val apples = 4
//before 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(f"I have $apples%d apples")
```

上記のコードは以下のように出力する。
```text
I have 4 apples
```


### [[Swift (プログラミング言語)|Swift]]
Swiftでは、定数・変数・リテラル・式の組合せから、それらの値を文字列リテラルの中に含むことによって、新しい文字列の値を作ることができる。文字列リテラルに含むそれぞれのアイテムは、一対の括弧で囲まれ、その前にバックスラッシュ（日本語環境では円記号）が置かれる。


```fsharp
let apples = 4
print("I have \(apples) apples")
```
上記のコードは以下のように出力する。

```text
I have 4 apples
```


### [[TypeScript]]
バージョン1.4より、TypeScriptはバッククォート ```` を使用した文字列補間に対応した。以下はその例である。

```ecmascript
var apples: number = 4;
console.log(`I have ${apples} apples`);
```

上記のコードは以下のように出力する。

```text
I have 4 apples
```

`console.log`関数は`printf`関数と同じように使用できる。上記の列は、以下のようにも書き表せる。

```ecmascript
var apples: number = 4;
console.log("I have %d apples", apples);
```


## 関連項目
* 文字列連結
* 
* printf
* 
* 

## 出典