文字型

文字型はStringで指定します。変数の宣言時に"(ダブルクォーテーション)で囲まれた文字列を代入すると暗黙的にString型となります。


let name: String
var job = "戦士"
var number = String(123)   // "123"

特殊文字

文字列中に以下のような特殊文字を含めることができます。

文字 意味
\0 ヌル文字
\\ バックスラッシュ
\t 水平タブ
\n ラインフィード
\r 改行
\" ダブルクォート
\' シングルクォート
\u{nn} 1バイトのユニコードスカラ値(nnは2桁の16進数値)
\u{nnnn} 2バイトのユニコードスカラ値(nnnnは4桁の16進数値)
\u{nnnnnnnn} 4バイトのユニコードスカラ値(nnnnnnnnは8桁の16進数値)


let message = "He said, \"I\'m going to be a king of pirates!\""
let atmark = "\u{40}"     // @
let heart = "\u{2665}"    // ♥︎

文字列の操作

空文字

空文字は以下のようにして定義できます。


var name1 = ""
var anme2 = String()

また、空文字かどうかは、isEmptyプロパティで判定できます。


if name1.isEmpty {
    print("名前はまだない")
}

長さを調べる

文字列の長さは、countElements関数で調べることができます。


var text = "Swiftの学習"
print(countElements(text))    // 8

連結

文字列を連結するには、+または、+=演算子を使います。


let prefix = "今日の天気は"
let weather = "晴れ"
let suffix = "です。"
var message = prefix + weather  // 今日の天気は晴れ
message += suffix               // 今日の天気は晴れです。

他の型と連結するには、文字列に変換してから連結します。


var hitPoint = 10
var message = "スライムのHPは" + String(hitPoint) + "です。" // スライムのHPは10です。

StringとCharacter同士も+演算子でそのまま連結することはできないので変換が必要です。


let hello: String = "Hello"
let mark: Character = "!"
print(hello + String(mark))

但し、appendメソッドで連結することは可能です。


var hello: String = "Hello"
let mark: Character = "!"

hello.append(mark)  // Hello!

補完

文字列中に、\( と ) で囲んで変数の値を含めることができます。


var hitPoint = 10
var message = "スライムのHPは\(hitPoint)です。" // スライムのHPは10です。

計算式や関数の呼び出しを含めることもできます。


var formula = "2 x 3 = \(2*3)"      // 2 x 3 = 6
var message = "結果は\(someFunc())"  // 結果は???

比較

文字列の比較には数値の場合と同様、==、<、<=、>、>= が使用できます。


let a = "A"
let b = "B"
if a == b {
    print("同じ")
} else if a < b {
    print("\(a)より\(b)の方が大きい")
} else {
    print("\(b)より\(a)の方が大きい")
}

StringのhasPrefix、hasSuffixメソッドで、文字列の前方と後方にそれぞれ指定した文字列が含まれるか判定することができます。


let a = "醤油ラーメン"
let b = "みそラーメン"
let c = "味噌汁"
print(a.hasPrefix("みそ"))  // false
print(b.hasPrefix("みそ"))  // true
print(c.hasPrefix("みそ"))  // false
print(a.hasSuffix("ラーメン"))  // true
print(b.hasSuffix("ラーメン"))  // true
print(c.hasSuffix("ラーメン"))  // false

文字列を大文字、小文字に変換するには、StringのuppercaseString、lowercaseStringメソッドを使用します。


let a = "This is a pen."
print(a.uppercaseString)  // THIS IS A PEN.
print(a.lowercaseString)  // this is a pen.

String型はCharacter型(ユニコード文字)の集りとみなすことができます。forループで回して文字列から1つずつCharacter型の変数に取り出すことができます。


var dog: Character = "dog.png"
print(dog)

let str = "Hello, 世界!"
for ch in str { // chはCharacter型
    print(ch)
}
/*
H
e
l
l
o
,
 
世
界
!
*/

部分文字列

指定した位置以降の文字列を取り出すには、substringFromIndexメソッドを使います。また、指定した位置まで文字列を取り出すには、substringToIndexメソッドを使います。

但し、substringToIndexメソッドにはString.Index型を渡す必要があるので少々面倒です。Int型の数値は直接渡せません。


let str = "abcdefghij"
var idx: String.Index
idx = advance(str.startIndex, 3)         // advance関数で位置3のインデックスを取得
print(str.substringFromIndex(idx))     // defghij
idx = advance(str.startIndex, 5)         // advance関数で位置5のインデックスを取得
print(str.substringToIndex(idx))       // abcde

NSStringにキャストしてやると、数値をそのままインデックスとして使用できます。


print((str as NSString).substringFromIndex(3))     // defghij
print((str as NSString).substringToIndex(5))       // abcde

substringFromIndexとsubstringToIndexを組み合わせると部分文字列を取り出すことができます。


let str = "abcdefghij"
let startIndex = advance(str.startIndex, 3)
let endIndex = advance(str.startIndex, 5)
print(str.substringFromIndex(startIndex).substringToIndex(endIndex))    // defgh

部分文字列を取り出すには、substringWithRangeメソッドを使う方法もあります。こちらは、String.Index型のRangeを渡す必要があります。(Int型のRangeではありません。)


let str = "abcdefghij"
let startIndex = advance(str.startIndex, 2)   // advance関数で位置2のインデックスを取得
let endIndex = advance(str.startIndex, 5)     // 同じく位置5のインデックスを取得
print(str.substringWithRange(startIndex..<endIndex)) // cde
print(str.substringWithRange(startIndex...endIndex)) // cdef

検索

指定した文字列が含まれるかどうか調べるには、rangeOfStringメソッドが使用できます。rangeOfStringメソッドは、String.Index型のRangeを返すので、Range.isEmptyを調べることで、文字列が含まれるかどうか調べることができます。


let str = "abcdefghij"
if let r = str.rangeOfString("def") {
    print("見つかった")
} else {
    print("見つからない")
}

rangeOfStringメソッドにオプションを指定することで、大文字小文字を無視した検索も可能です。(NSStringで使用するNSStringCompareOptionsと同様のオプションを指定できます。)


let str = "abcdefghij"
if let r = str.rangeOfString("DeF", options:.CaseInsensitiveSearch) {
    print("見つかった")
}

文字列補完

文字列の中に、他の変数の値や計算結果を埋め込むことができます。


let title = "円の面積"
let pi = 3.14
var radius = 20
// 円の面積: 3.14 x 20 x 20 = 1256.0
let str = "\(title): \(pi) x \(radius) x \(radius) = \(pi * Double(radius) * Double(radius))"

ユニコード

スカラー値とサロゲートペア

Swiftは、ユニコードを強力にサポートする言語で、Stringは内部的にユニコードの21ビットスカラー値で表現されています。これは文字コードにUTF-16を使っているObjective-Cとは異なります。
ユニコードのスカラー値は、U+0000〜U+D7FFU+E000〜U+10FFFFのコードポイントで表現されます。ここで除外されているU+D800〜U+DFFFはサロゲート(代用)と呼ばれ、スカラー値には含まれません。このU+D800〜U+DBFFの前半部分と、U+DC00〜U+DFFFの後半部分のそれぞれ1024文字分ずつの組み合わせ(ペア)をサロゲートペアと呼び、BMP(基本他言語面)以外の拡張文字等を表現するために使用されます。
21ビットの各スカラー値の全てが、Character型の文字として割り当てらているわけではなく、一部は将来の目的のために予約されています。

書記素クラスタ

ユニコードには、書記素クラスタと呼ばれる、それ単独では文字として成り立たなくても、他の文字と組み合わせることで単独の文字となる要素があります。

例えば、éはコードポイントU+00E9で表現されますが、e(U+0065)とアクセント記号(U+0301)の組み合わせでも表現できます。そしてこれらは何れも単一のCharacter型となります。また、これらを比較すると同一文字として認識されます。


// どちらもé
var a, b: Character
a = "\u{00e9}"          // é
b = "\u{0065}\u{0301}"  // é
print(a == b)         // true

逆に、見た目は同じでもコードポイントが異なる文字もあります。これらの比較結果は同一文字とはみなされません。


let a = "\u{0041}"  // 英語のA
let b = "\u{0410}"  // ロシア語のА
print(a == b)     // false 文字としては別物

また、文字を装飾するために使用される書記素クラスタもあります。例えば、U+20DDは、直前の文字を○で囲みます。


var c = "\u{E9}\u{20DD}"     // ecircle.png
var d = "ア\u{20DD}"         // ㋐

これらも1文字を構成するコードポイントは複数になりますが、実際の文字としては1文字となります。

この様に、ユニコードのスカラー値で構成された文字列の長さは単純にバイト数で判断できないため、Swiftでは、String型の長さを調べるために、countElements(...)というグローバル関数が用意されています。これは文字列の頭からカウントしながら文字数を調べるため長い文字列の場合はその分、時間がかかることになります。


countElements("アイウエオ")   // 5
countElements("ア\u{20DD}")  // 1

CocoaのNSStringは、lengthプロパティで長さを取得できますが、これはUTF16文字列の16ビットコードの長さを元に算出しているため、書記素クラスタによる装飾を反映できない場合があります。そのため、同じ文字列であっても、SwiftのcountElements(...)で返される値と、NSStringのlengthプロパティの値は一致しない可能性があります。(文字数という意味ではSwiftのStringの方が正確です。)

文字列のエンコード

Swiftの文字列は、 ユニコードのUTF-8、UTF-16、UTF-32の各表現形式へエンコードできます。

UTF-8形式は、Stringのutf8プロパティで取得できます。


let str = "I \u{1F496} caf\u{E9}"   // I heart.png café
for c in str.utf8 {
    print(NSString(format: "%2X", c)); print(" ")
}
// 49 20 F0 9F 92 96 20 63 61 66 C3 A9
//
// 0x49 = "I"
// 0x20 = " "
// 0xF0 0x9F 0x92 0x96 = "heart.png"
// 0x20 = " "
// 0x63 = "c"
// 0x61 = "a"
// 0x66 = "f"
// 0xC3 0xA9 = "é"

UTF-16形式は、Stringのutf16プロパティで取得できます。


let str = "I \u{1F496} caf\u{E9}"   // I heart.png café
for c in str.utf16 {
    print(NSString(format: "%04X", c)); print(" ")
}
// 0049 0020 D83D DC96 0020 0063 0061 0066 00E9
//
// 0x0049 = "I"
// 0x0020 = " "
// 0xD83D 0xDC906 = "heart.png"
// 0x0020 = " "
// 0x0063 = "c"
// 0x0061 = "a"
// 0x0066 = "f"
// 0x00E9 = "é"

UTF-32形式は、21ビットのスカラー値をそのまま32ビットで表現した形式です。StringのunicodeScalarsプロパティで取得できます。


let str = "I \u{1F496} caf\u{E9}"   // I heart.png café
for c in str.unicodeScalars {
    print(NSString(format: "%08X", c.value)); print(" ")
}
// 00000049 00000020 0001F496 00000020 00000063 00000061 00000066 000000E9
//
// 0x00000049 = "I"
// 0x00000020 = " "
// 0x0001F496 = "heart.png"
// 0x00000020 = " "
// 0x00000063 = "c"
// 0x00000061 = "a"
// 0x00000066 = "f"
// 0x000000E9 = "é"

UnicodeScalar

UnicodeScalarは、ユニコードの1文字を表現する構造体です。次の例ではASCII値から文字を生成し、"A"〜"Z"の文字を連結しています。


var str: String = ""
for ch in 65..<(65 + 26) {
    str += Character(UnicodeScalar(ch))
}
print(str)    // ABCDEFGHIJKLMNOPQRSTUVWXYZ