はじめに
公式ドキュメントのうち、ほぼ同じ内容の部分を排除して、ざっくりと日本語訳した。具体例とかは削りぎみ(最後の方直訳っぽくなってしなったので修正したい)
内容の抜け落ちは殆ど無いはず
ざっくり全部日本語で読みたい人用
Swift 2.2の資料を元に書いています
間違い、修正すべき点など遠慮無くコメントでお願いします
String and Characters
CharacterのCollectionとしてなど、様々な方法でアクセスできる
String Literal
""でくくったのがStringのリテラル
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
これらは同じ
emptyString.isEmpty()
で空文字かどうか判断できる
String Mutability
varなら変更可能、letなら変更不可
letなのに変更しようとすると、コンパイル時にエラーがでる
Strings Are Value Types
StringはValue Type = 値渡し
自分が変更しないなら、変更されてないことが保証される
Working with Characters
.characters
プロパティを呼び出すと、一文字ずつCharacter型のオブジェクトとして取り出せる
for character in "Dog!🐶".characters {
print(character)
}
D
o
g
!
🐶
for-in
ループについてはこちら
もしくは独立に、一文字のStringリテラルからも、Character型の変数/定数を作れる
let exclamationMark: Character = "!"
CharacterのArrayをStringのイニシャライザに渡すと、合体したStringを作れる
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
Cat!🐱
Concatenating Strings and Characters
文字列の結合。Stringはoperator (+) で新しいStringが作られる(そしてこれを代入すれば更新できる)
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcomeは"hello there"と等しくなる
operator (+=) でも同様に動く
CharacterをStringに追加するには、String型のappend()メソッドを使う
let exclamationMark: Character = "!"
var welcome = "hello there".append(exclamationMark)
// welcome now equals "hello there!"
ただし、Characterは一文字しか保持できないので、Characterに対して文字やCharacterを追加することは出来ない
Momo:
StringのArrayは.joinWithSeparator()
メソッドで結合できる
String Interpolation
String interpolationとは、定数・変数・リテラル・式の値をStringリテラルの中にいれて、新しいStringをつくること
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"
"\(multiplier)"というプレースホルダが、実際の値に置き換えられる
ちなみに、()内には、エスケープされていないバックスラッシュ、改行コードは入れられないが、その他はいられる
Unicode
Unicodeは国際的な、エンコーディングの標準
Swiftにおける、StringやCharacterは、完全にUnicodeに準拠している。(本節参照)
Unicode Scalars
SwiftでのString型は、裏では、UnicodeScalar値から作られている
UnicodeScalar値は、文字や記号に対応する、
- U+0061 は LATIN SMALL LETTER A ("a")
- U+1F425 は FRONT-FACING BABY CHICK ("🐥")
といった21ビットのユニークな数字
ただし、Unicodeスカラー値は全て文字に割り当てるわけではなく、未来のための予約語もある。また、割り当てられてる文字には、上で示した、 LATIN SMALL LETTER AやFRONT-FACING BABY CHICKといった名前もあることも多い
Special Characters in String Literals
Stringリテラルの中にも特殊文字を入れられる(本節参照)
- エスケープされた特殊文字
エスケープ | 表示 |
---|---|
\0 | null character |
\\ | backslash |
\t | horizontal tab |
\n | line feed |
\r | carriage return |
\" | double quote |
' | single quote |
- "\u{n}"
"\u{n}"として、nは、1–8桁の16進数にすると、任意のユニコード文字を入れられる(Unicodeのコードポイントが存在するもののみ)
以下、特殊文字の例
wiseWords定数は2つのダブルコーテーションを含む。
その他のdollarSign, blackHeart, sparklingHeartはユニコードスカラー値フォーマットの例
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\u{24}" // $, Unicode scalar U+0024
let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
Extended Grapheme Clusters
SwiftのCharacter型のインスタンスは、全て1つのextended grapheme clusterを示す。1つのextended grapheme clusterは、1つの人間が読める文字を表す
(Unicodeスカラー値は1つまたは複数合わさってextended grapheme clusterを構成する)
※ grapheme cluster = 書記素クラスタ
例:
"é"は、
ユニコードスカラー値é (LATIN SMALL LETTER E WITH ACUTE, or U+00E9)
でも表せるが
e (LATIN SMALL LETTER E, or U+0065) + COMBINING ACUTE ACCENT scalar (U+0301)
という組み合わせでも表現できる
COMBINING ACUTE ACCENT scalarは前の文字に適用されて、Unicode対応のテキストレンダリングシステムによって描画される時に、e + COMBINING ACUTE ACCENTはéに変わる
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
// eAcute is é, combinedEAcute is é
Extended grapheme clustersによって、とても柔軟に、多くの複雑な文字を、一つのCharacter型の値として表せる
ハングルの音節は、precomposedとdecomposed sequenceのどちらでも表せるが、Swiftではどちらも、1つのCharacter型の値としてみなされる。
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한
Extended grapheme clustersのおかげで、囲いマークで他のUnicode文字を囲って、一つのCharacter型の値として扱える (例: COMBINING ENCLOSING CIRCLE, U+20DD)
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute is é⃝
regional indicator symbolsに対応するUnicodeスカラは、単一のCharacter型の値を作るために、pairsに結合される
例:
REGIONAL INDICATOR SYMBOL LETTER U (U+1F1FA)と、REGIONAL INDICATOR SYMBOL LETTER S (U+1F1F8)との組み合わせ
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS is 🇺🇸
Counting Characters
Stringの中のCharacterの数を調べたいなら、String.charactersのcountプロパティを使う
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
// Prints "unusualMenagerie has 40 characters"
ただし、SwiftのCharacterはextended grapheme clustersを使っているので、Stringの結合/修正しても、character.countに影響を与えないこともある
例:
4文字の単語"word"にCOMBINING ACUTE ACCENT (U+0301)を追加しても、結果のcharacters.countは4のまま。4文字目は、eでなくéになっている
var word = "cafe"
print("the number of characters in \(word) is \(word.characters.count)")
// Prints "the number of characters in cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.characters.count)")
// Prints "the number of characters in café is 4"
Extended grapheme clustersは1つまたは複数のUnicodeScalarから構成されるので、違う文字、さらには同じ文字の違う表現は、使うメモリの量が異なる可能性がある。
たとえ同じ文字列の中であっても、各charactersがおなじ量のメモリを使うわけではなので、文字数はString全てをiterateしないと、extended grapheme clusterの境界がわからず、文字数を数えられない
特に、長いString値を扱う時には、.charactersプロパティは、String中の全てのUnicodeスカラをイテレートしなきゃ決定できないことを知っておいてください
NSString型の.length
は、UTF-16に基づいているので、.characters.count
の結果は、(NSString).lengthの結果と違うこともある。
Accessing and Modifying a String
メソッド、プロパティ、サブスクリプト等でStringを取得・修正できる
String Indices
各String型の値には、関連づいたString.Index型があって、各Characterの位置に対応している
上で述べたように、各Characterの必要とするメモリ容量がわからないので、各UnicodeScalarを先頭もしくは末尾からiterateしないと、どのCharacterがその位置にあるのか特定できない
そのため、SwiftのStringでは、Integerでインデックス出来ない
.startIndex
プロパティはStringの先頭のCharacterの位置を、.endIndex
プロパティはStringの末尾のCharacterの次の位置を表す。よって、.endIndex
はsubscriptとして有効ではない。(例2参照)
Stringが空の時、.startIndex
は.endIndex
と等しい
String.Index
の値は、predecessor()
メソッドを呼ぶと直前の文字に、successor()
メソッドを呼ぶと直後の文字にアクセスできる
Stringの文字は全て、他のIndexから、このメソッドを繋げるか、もしくはadvancedBy(_:)
メソッドを使ってアクセスできる。
もしStringの範囲外のindexを指定すると、runtime errorが発生する
特定のindexにあるCharacterは、subscriptでアクセスできる
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.endIndex.predecessor()]
// !
greeting[greeting.startIndex.successor()]
// u
let index = greeting.startIndex.advancedBy(7)
greeting[index]
// a
範囲外にアクセスするとエラー
greeting[greeting.endIndex] // error
greeting.endIndex.successor() // error
.characters.indices
プロパティは、各CharacterにアクセスするためのindexesのRange
を生成するので、各Characterを読み出せる
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: "")
}
// prints "G u t e n T a g ! "
Inserting and Removing
Stringの特定の位置に文字を挿入するには、insert(_:atIndex:)
メソッドを使う
var welcome = "hello"
welcome.insert("!", atIndex: welcome.endIndex)
// welcome now equals "hello!"
特定の位置に別の文字列を挿入するには、insertContentsOf(_:at:)
メソッドを使う
welcome.insertContentsOf(" there".characters, at: welcome.endIndex.predecessor())
// welcome now equals "hello there!"
特定の位置のCharacterを削除するには、removeAtIndex(_:)
メソッドを使う
welcome.removeAtIndex(welcome.endIndex.predecessor())
// welcome now equals "hello there"
特定の範囲のサブ文字列を削除するには、removeRange(_:)
メソッドを使う
let range = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
// welcome now equals "hello"
Comparing Strings
Swiftには、テキストの値を比較する方法が3つある
- 文字・文字列の等しさ
- prefixの等しさ
- suffixの等しさ
String and Character Equality
文字・文字列が等しいかは、==
, !=
で評価できる(参照:比較演算子)
let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."
if quotation == sameQuotation {
print("These two strings are considered equal")
}
// Prints "These two strings are considered equal"
2つの文字/文字列は、extended grapheme clustersが正準等価(canonically equivalent)なときに等しいとみなされる。extended grapheme clustersは、言語的意味、見た目が同じなら、裏では違うUnicode scalarsからできていても、正準等価である
例:
LATIN SMALL LETTER E WITH ACUTE (U+00E9)は
LATIN SMALL LETTER E (U+0065) + COMBINING ACUTE ACCENT (U+0301)
と等価
これらはともにéを表す。
// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
// "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
if eAcuteQuestion == combinedEAcuteQuestion {
print("These two strings are considered equal")
}
// Prints "These two strings are considered equal"
逆に、アメリカで使われるような、
LATIN CAPITAL LETTER A (U+0041, or "A")
と、ロシアで使われるような
CYRILLIC CAPITAL LETTER A (U+0410, or "А")
は等価ではない。
これらは見た目は似ているが、言語的な意味は異なる。
let latinCapitalLetterA: Character = "\u{41}"
let cyrillicCapitalLetterA: Character = "\u{0410}"
if latinCapitalLetterA != cyrillicCapitalLetterA {
print("These two characters are not equivalent")
}
// Prints "These two characters are not equivalent"
Note:
Swiftにおける文字・文字列の比較は、localeによって出来たり出来なかったりするようなものではないです
Prefix and Suffix Equality
文字列が特定の接頭辞・接尾辞を持っているかは、hasPrefix(_:)
メソッド、hasSuffix(_:)
メソッドを用いる。共にStringを受け取り、Boolを返す
下記の例は、ロミオとジュリエット/シェイクスピアのはじめの2幕の各シーンの舞台を表すStringのArray
let romeoAndJuliet = [
"Act 1 Scene 1: Verona, A public place",
"Act 1 Scene 2: Capulet's mansion",
"Act 1 Scene 3: A room in Capulet's mansion",
"Act 1 Scene 4: A street outside Capulet's mansion",
"Act 1 Scene 5: The Great Hall in Capulet's mansion",
"Act 2 Scene 1: Outside Capulet's mansion",
"Act 2 Scene 2: Capulet's orchard",
"Act 2 Scene 3: Outside Friar Lawrence's cell",
"Act 2 Scene 4: A street in Verona",
"Act 2 Scene 5: Capulet's mansion",
"Act 2 Scene 6: Friar Lawrence's cell"
]
hasPrefix(_:)
メソッドを使えば、Act 1のシーンの数を数えられる
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
act1SceneCount += 1
}
}
print("There are \(act1SceneCount) scenes in Act 1")
// Prints "There are 5 scenes in Act 1"
同様に、hasSuffix(_:)
メソッドを使えば、Capulet’s mansionの中や、Friar Lawrence’s cellの近くのシーンの数を数えられる
var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
if scene.hasSuffix("Capulet's mansion") {
mansionCount += 1
} else if scene.hasSuffix("Friar Lawrence's cell") {
cellCount += 1
}
}
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// Prints "6 mansion scenes; 2 cell scenes"
Note:
hasPrefix(_:)
、hasSuffix(_:)
メソッドは、各文字列のextended grapheme clusters同士で、文字単位の正準等価(canonical equivalence)の比較を行う(String and Character Equality参照)
Unicode Representations of Strings
Unicode文字列がテキストファイル等に書きだされたら、文字列中のUnicodeScalarsは何らかのUnicodeで使えるエンコーディング形式にエンコードされる。
各形式は、code unitとして知られる小さなchunkに文字列をエンコードする。
UTF-8形式(8-bit code unitsとして文字列をエンコードする)や、UTF-16形式(16-bit code unitsとして文字列をエンコードする)や、UTF-32形式(32-bit code unitsとして文字列をエンコードする)なども含む。
SwiftにはいくつかUnicode表現にアクセスする方法がある
for-in
構文でstring全てiterateすれば、各Unicode extended grapheme clusterにアクセスできる(Working with Characters参照)
他にも、3つのUnicode準拠の表現のいずれかでもStringの値にアクセスできる
- UTF-8のcode unitの集まり
- UTF-16のcode unitの集まり
- 21-bitのUnicodeScalar値(UTF-32形式と等価)
それぞれ、.utf8
プロパティ、utf16
プロパティ、.unicodeScalars
プロパティでアクセスできる
以下に示す各例は、"Dog‼🐶"の異なる表現である。これは、
D,
o,
g,
‼ (DOUBLE EXCLAMATION MARK, or Unicode scalar U+203C),
🐶 character (DOG FACE, or Unicode scalar U+1F436)
からできている
let dogString = "Dog‼🐶"
UTF-8 Representation
.utf8
プロパティをiterateすれば、UTF-8表現を得られる。これはString.UTF8View型で、UTF8表現の各バイト対応するUInt8型(unsigned 8-bit)の値の集まり
for codeUnit in dogString.utf8 {
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 111 103 226 128 188 240 159 144 182
上の例では、最初の3つの数字(68, 111, 103)がD, o, gを表す。これはASCII表現と同じ。
その次の3つのcodeUnitの値(226, 128, 188)は、3バイトの、DOUBLE EXCLAMATION MARKのUTF-8表現で、最後の4つのcodeUnitの値(240, 159, 144, 182)は4バイトの、DOG FACEのUTF-8表現。
UTF-16 Representation
.utf16
プロパティをiterateすれば、UTF-16表現を得られる。これはString.UTF16View型で、UTF16表現の各16-bitのcode unitに対応するUInt16型(unsigned 16-bit)の値の集まり
for codeUnit in dogString.utf16 {
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 111 103 8252 55357 56374
繰り返すが、はじめ3つのcodeUnitの値(68, 111, 103)はD、o、gを表し、これはUTF-8の値と同じ。(何故ならUnicodeScalarはASCII文字を表現しているから)
4番目のcodeUnitの値(8252)は10進数で、16進数の203Cと等価。つまりUnicodeScalarの"U+203C"であるDOUBLE EXCLAMATION MARKを表す。これはUTF-16では単一のcode unitで表現される
5, 6番目のcodeUnitの値(55357, 56374)はDOG FACEのサロゲートペア(1つの文字を表す連続した2つのcode pointのペア)。
ここでは、high-surrogate valueはU+D83D(10進数で55357)、low-surrogate valueはU+DC36(10進数で56374)
Unicode Scalar Representation
.unicodeScalars
プロパティをiterateすれば、Unicode scalar表現を得られる。これはUnicodeScalarView型で、UnicodeScalar型の値の集まり
各UnicodeScalarは.value
プロパティを持ち、scalarの21-bitの値を返す。これはUInt32型として渡される
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ", terminator: "")
}
print("")
// 68 111 103 8252 128054
はじめ3つのUnicodeScalarの値(68, 111, 103)のvalueプロパティは、ここでもD、o、gを表す
4番目のcodeUnitの値(8252)は、ここでも、10進数で16進数の203Cと等価で、UnicodeScalarの"U+203C"であるDOUBLE EXCLAMATION MARKを表す。
5, 6番目のUnicodeScalarの.value
プロパティ(128054)は、10進数で、16進数の1F436と等価。これはUnicode scalarのU+1F436、つまりDOG FACEを表す。
他にも、.value
プロパティを得る方法としてだが、各UnicodeScalar値は、string interpolationみたいに新しいStringを作るのにも使える
for scalar in dogString.unicodeScalars {
print("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶