SwiftのStringの定義方法まとめ

Swiftで文字列の定義方法が増えてきたのでまとめました。

*執筆時点のSwiftのバージョンは5.1です。*


|  | 基本 | 複数行 | 基本 + 拡張デリミタ | 複数行 + 拡張デリミタ |
|:-:|:--|:--|:--|:--|
| **書き方** | `"文字列"` | `"""`<br>`文字列1`<br>`文字列2`<br>`"""` | `#"文字列"#` | `#"""`<br>`文字列1`<br>`文字列2`<br>`"""#` |
| **改行** | `\n` | そのまま改行 <br>`\n`も利用可 | `\#n` | そのまま改行 <br>`\#n`も利用可 |
| **エスケープ** | `\` | `\` | `\#` | `\#`
| **用途** | 単一行 | 複数行 | 単一行で`\`が多い | 複数行で`\`が多い

## 基本

### 書き方

Swiftで文字列のリテラルを定義するには、対象の文字列を`"`（ダブルクオーテーション）の引用符で囲みます。

```swift
let text = "ABC"  // 出力結果: ABC
```

### 改行

改行したい場合は、`\n`(LF)[^1]を利用します。
文字列の複数行の定義はできません。

```swift
let text = "ABC\nDEF"
/* 出力結果
ABC
DEF
*/

let text = "ABC
DEF"  // 複数行定義すると文法エラー
```
[^1]: CRを使いたい場合は`\r`です。

### エスケープ

特殊文字[^2]のエスケープには`\`を使います。
例えば、引用符の`"`を文字列として定義したい場合は`\"`とします。
`\`自体を定義したい場合は、`\`を2つ続けます。

```swift
let doubleQuotation = "\""  // 出力結果: "
let backslash = "\\"        // 出力結果: \
```

[^2]: 本文で出てくる`\"`・`\\`・`\n`・`\r`以外にも、あまり使いませんが`\t`(水平タブ)や`\0`(null)も使えます。

### 用途

どんな用途でも対応可能です。
しかし、現在は後述の便利で読みやすい書き方ができるので、この書き方はシンプルな文字列の定義の時に使うのが良いでしょう。

## 複数行

Swift4([SE-0168](https://github.com/apple/swift-evolution/blob/master/proposals/0168-multi-line-string-literals.md))から導入された、複数行の文字列を定義できる書き方です。

### 書き方

複数行の場合は引用符が`"""`になります。
書き方は「`"""` + 改行 + 対象文字列 + 改行 + `"""`」です。
（前後の改行は必須で無い場合はエラーとなります。）
対象文字列には複数行の文字列を指定できます。

```swift
let multiLine = """
ABC
DEF
"""
/* 出力結果（複数行の文字列がそのまま出力される）
ABC
DEF
*/
```

### 改行

改行したい場合は、定義している文字列の中で改行すればそのまま改行として扱われます。
もちろん、従来の`\n`(LF)[^1]を使うこともできます。
なお、対象文字列の前後の改行は、文字列としては無視されます。

逆に文字列の中で改行してもそれを改行としたくない場合は、`\`を行末に指定します。

```swift
let singleLine = """
ABC\
DEF
"""
/* 出力結果（ABCの後に\があるので改行が無視される）
ABCDEF
*/
```

### エスケープ

`"`はエスケープ不要でそのまま書くことができます。
それ以外の文字（`\`など）のエスケープには、基本と同じく`\`を使います。
（`"`をエスケープすることもできますが、冗長になるだけです。）

```swift
let multiLine = """
"ABC"
\\
"""
/* 出力結果
"ABC"
\
*/
```

`"""`を定義したい場合は、どれか1つ以上の`"`をエスケープします。

```swift
let doubleQuotation = """
先頭1つだけ \"""
3つ全て \"\"\"
先頭と最後の2つ \""\"
"""
/* 出力結果
先頭1つだけ """
3つ全て """
先頭と最後の2つ """
*/
```

「どれか1つ以上」なので上のサンプルのようにいろいろなパターンが使えますが、可読性を考えると全部またはどれか1つだけに統一して使った方が良いでしょう。

### インデント

複数行の定義方法ではインデントが自動で調整されます。
インデントは閉じる方の`"""`の位置が基準となり、それより前の空白(タブ含む)は無視されます。

```swift
let multiLine = """
    ABC
        DEF
    """
/* 出力結果（ABCやDEFの前の4スペース分は無視される）
ABC
    DEF
*/
```

これによりメソッドの中などで文字列を定義する時に、周りのコードとインデントを揃えることができ読みやすくなります。

### 用途

複数行のテキストを定義する時に便利です。
また、`"`のエスケープも不要なので、JSONやXML/HTMLを定義する時に最適です。

## 拡張デリミタ（区切り文字）

Swift5([SE-0200](https://github.com/apple/swift-evolution/blob/master/proposals/0200-raw-string-escaping.md))から導入された、エスケープを無視した生(Raw)の文字列を定義できる書き方です。

基本の書き方と複数行の書き方、両方に組み合わせて定義します。

### 書き方

文字列の定義の前後を、`#`で囲みます。
基本の場合は「`#"` + 対象文字列 + `"#`」となります。
複数行の場合は「`#"""` + 改行 + 対象文字列 + 改行 + `"""#`」です。

特徴的なのは`\`がエスケープ文字として認識されないという点です。

```swift
let text = #"ABC\nDEF"#
/* 出力結果（通常は改行となる\nがそのまま文字列となる）
ABC\nDEF
*/

let multiLine = #"""
ABC\\DEF
"""#
/* 出力結果（\がエスケープされずそのまま文字列となる）
ABC\\DEF
*/
```

### 改行

改行したい場合は、`\#n`(LF)を利用します。

```swift
let text = #"ABC\#nDEF"#
/* 出力結果
ABC
DEF
*/
```

複数行の場合は、そのまま改行する方法も使えます。
また、複数行で改行としたくない場合は、`\#`を行末に指定します。

### エスケープ

特殊文字をエスケープしたい場合、エスケープ文字には`\`ではなく`\#`を使います。

文字列の中で`"#`を定義したい場合は引用符の`#`を追加[^3]して「`##"` + 対象文字列 + `"##`」とします。
複数行の場合は「`##"""` + 改行 + 対象文字列 + 改行 + `"""##`」です。

```swift
let text = ##"ABC"#DEF"##
/* 出力結果
ABC"#DEF
*/
```

[^3]: 今回は1つ追加して`#`を2つにしましたが、実は3つ以上追加することもできます。`#`を追加した場合のエスケープ文字は「`\` + 引用符につけた`#`と同じ数の`#`」となります。例えば、`#`を4つ追加したら`\####`です。

### 用途

エスケープ処理をさせたくない場合、書いた文字列をそのまま文字列としたい場合に使います。
例えば、正規表現のように`\`をよく使う文字列の場合はシンプルに書けるので大変便利です。

```swift
let bad = "[\\l\\d\\r\\n]*" // 通常だとエスケープの`\`が必要
let good = #"[\l\d\r\n]*"#  // エスケープの`\`が無いので便利
```