参考資料

文字列と文字

文字列は「hello, world」や「albatross」のような一連の文字です。Swiftの文字列はString型で表されます。Stringの内容には、Character値のコレクションとしてなど、さまざまな方法でアクセスできます。

文字列と文字

文字列"hello, world""albatross"のような一連の文字です。Swiftの文字列はString型で表されます。Stringの内容には、Character値のコレクションとしてなど、さまざまな方法でアクセスできます。

SwiftのString型とCharacter型は、コード内でテキストを扱うための高速でUnicode準拠の方法を提供します。文字列の作成と操作の構文は軽量で読みやすく、C言語に似た文字列リテラル構文を持っています。文字列の連結は+演算子で2つの文字列を組み合わせるだけで簡単に行え、文字列の可変性はSwiftの他の値と同様に定数か変数かを選択することで管理されます。また、文字列補間と呼ばれるプロセスを使用して、定数、変数、リテラル、および式をより長い文字列に挿入することもできます。これにより、表示、保存、印刷用のカスタム文字列値を簡単に作成できます。

この構文の単純さにもかかわらず、SwiftのString型は高速で現代的な文字列実装です。すべての文字列はエンコーディングに依存しないUnicode文字で構成されており、さまざまなUnicode表現でそれらの文字にアクセスするためのサポートを提供しています。

Note SwiftのString型はFoundationのNSStringクラスとブリッジされています。FoundationはまたStringを拡張して、NSStringで定義されたメソッドを公開しています。これは、Foundationをインポートすれば、キャストなしでString上でそれらのNSStringメソッドにアクセスできることを意味します。

StringをFoundationおよびCocoaで使用する方法の詳細については、Bridging Between String and NSStringを参照してください。

文字列リテラル

事前に定義されたString値を文字列リテラルとしてコード内に含めることができます。文字列リテラルは、二重引用符(")で囲まれた一連の文字です。

定数または変数の初期値として文字列リテラルを使用します:

let someString = "Some string literal value"

someString定数は文字列リテラル値で初期化されているため、SwiftはString型を推論することに注意してください。

複数行文字列リテラル

複数行にわたる文字列が必要な場合は、複数行文字列リテラルを使用します。これは3つの二重引用符で囲まれた一連の文字です:

let quotation = """
The White Rabbit put on his spectacles.  "Where shall I begin,
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""

複数行文字列リテラルには、開始引用符と終了引用符の間のすべての行が含まれます。文字列は開始引用符(""")の後の最初の行から始まり、終了引用符の前の行で終わります。つまり、以下の文字列はどちらも改行で始まったり終わったりしません:

let singleLineString = "These are the same."
let multilineString = """
These are the same.
"""

ソースコードが複数行文字列リテラル内に改行を含む場合、その改行は文字列の値にも表示されます。ソースコードを読みやすくするために改行を使用したいが、その改行を文字列の値の一部にしたくない場合は、それらの行の末尾にバックスラッシュ(\)を書きます:

let softWrappedQuotation = """
The White Rabbit put on his spectacles.  "Where shall I begin, \
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on \
till you come to the end; then stop."
"""

改行で始まるまたは終わる複数行文字列リテラルを作成するには、最初または最後の行として空行を書きます。例えば:

let lineBreaks = """

This string starts with a line break.
It also ends with a line break.

"""

複数行文字列は、周囲のコードに合わせてインデントできます。終了引用符(""")の前の空白は、他のすべての行の前で無視する空白をSwiftに伝えます。ただし、終了引用符の前にあるものに加えて行の先頭に空白を書く場合、その空白含まれます。

multilineStringWhitespace

上の例では、複数行文字列リテラル全体がインデントされていますが、文字列の最初と最後の行は空白で始まりません。中間の行は終了引用符よりも多くインデントされているため、追加の4スペースのインデントで始まります。

文字列リテラルの特殊文字

文字列リテラルには以下の特殊文字を含めることができます:

  • エスケープされた特殊文字:\0(ヌル文字)、\\(バックスラッシュ)、\t(水平タブ)、\n(改行)、\r(キャリッジリターン)、\"(二重引用符)、\'(単一引用符)
  • 任意のUnicodeスカラー値。\u{n}と記述し、nは1〜8桁の16進数です(Unicodeについては以下のUnicodeで説明しています)

以下のコードは、これらの特殊文字の4つの例を示しています。wiseWords定数には2つのエスケープされた二重引用符が含まれています。dollarSignblackHeartsparklingHeart定数はUnicodeスカラー形式を示しています:

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

複数行文字列リテラルは1つではなく3つの二重引用符を使用するため、エスケープせずに複数行文字列リテラル内に二重引用符(")を含めることができます。テキスト"""を複数行文字列に含めるには、引用符の少なくとも1つをエスケープします。例えば:

let threeDoubleQuotationMarks = """
Escaping the first quotation mark \"""
Escaping all three quotation marks \"\"\"
"""

拡張文字列デリミタ

拡張デリミタ内に文字列リテラルを配置して、特殊文字の効果を発動させずに文字列に含めることができます。文字列を引用符(")内に配置し、その周りをナンバーサイン(#)で囲みます。例えば、文字列リテラル#"Line 1\nLine 2"#を印刷すると、文字列を2行に印刷するのではなく、改行エスケープシーケンス(\n)が印刷されます。

文字列リテラル内の文字の特殊効果が必要な場合は、エスケープ文字(\)の後の文字列内のナンバーサインの数を一致させます。例えば、文字列が#"Line 1\nLine 2"#で改行したい場合は、代わりに#"Line 1\#nLine 2"#を使用できます。同様に、###"Line1\###nLine2"###も改行します。

拡張デリミタを使用して作成された文字列リテラルは、複数行文字列リテラルにすることもできます。拡張デリミタを使用して、リテラルを終了するデフォルトの動作をオーバーライドし、複数行文字列にテキスト"""を含めることができます。例えば:

let threeMoreDoubleQuotationMarks = #"""
Here are three more double quotes: """
"""#

空の文字列の初期化

より長い文字列を構築するための開始点として空のString値を作成するには、変数に空の文字列リテラルを割り当てるか、イニシャライザ構文で新しいStringインスタンスを初期化します:

var emptyString = ""               // empty string literal
var anotherEmptyString = String()  // initializer syntax
// these two strings are both empty, and are equivalent to each other

String値が空かどうかを調べるには、そのブールisEmptyプロパティをチェックします:

if emptyString.isEmpty {
    print("Nothing to see here")
}
// Prints "Nothing to see here".

文字列の可変性

特定のStringを変更できる(またはミュータブル)かどうかは、変数に割り当てる(変更可能な場合)か、定数に割り当てる(変更できない場合)かによって示します:

var variableString = "Horse"
variableString += " and carriage"
// variableString is now "Horse and carriage"

let constantString = "Highlander"
constantString += " and another Highlander"
// this reports a compile-time error - a constant string cannot be modified

Note このアプローチは、Objective-CとCocoaでの文字列のミューテーションとは異なります。Objective-Cでは、文字列をミュータブルにできるかどうかを示すために2つのクラス(NSStringNSMutableString)から選択します。

文字列は値型

SwiftのString型は値型です。新しいString値を作成すると、そのString値は関数またはメソッドに渡されるとき、または定数または変数に割り当てられるときにコピーされます。いずれの場合も、既存のString値の新しいコピーが作成され、元のバージョンではなく新しいコピーが渡されるか割り当てられます。値型については構造体と列挙型は値型で説明しています。

Swiftのデフォルトのコピー動作であるStringの動作により、関数またはメソッドがString値を渡すとき、そのString値はどこから来たものであっても、正確にそのString値を所有していることが明確になります。自分で変更しない限り、渡された文字列は変更されないと確信できます。

舞台裏では、Swiftのコンパイラは文字列の使用を最適化し、実際のコピーは絶対に必要な場合にのみ行われます。これは、文字列を値型として扱う場合でも常に優れたパフォーマンスが得られることを意味します。

文字の操作

Stringの個々のCharacter値には、for-inループで文字列を反復処理することでアクセスできます:

for character in "Dog!🐶" {
    print(character)
}
// D
// o
// g
// !
// 🐶

for-inループについてはFor-Inループで説明しています。

あるいは、Character型アノテーションを提供することで、単一文字の文字列リテラルからスタンドアロンのCharacter定数または変数を作成できます:

let exclamationMark: Character = "!"

String値は、Character値の配列をイニシャライザの引数として渡すことで構築できます:

let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
// Prints "Cat!🐱".

文字列と文字の連結

String値は加算演算子(+)で追加(または連結)して新しいString値を作成できます:

let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"

加算代入演算子(+=)を使用して、既存のString変数にString値を追加することもできます:

var instruction = "look over"
instruction += string2
// instruction now equals "look over there"

String型のappend()メソッドを使用して、String変数にCharacter値を追加できます:

let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome now equals "hello there!"

Note 既存のCharacter変数にStringまたはCharacterを追加することはできません。Character値には単一の文字のみを含める必要があるためです。

複数行文字列リテラルを使用してより長い文字列の行を構築する場合、最後の行を含む文字列のすべての行が改行で終わるようにする必要があります。例えば:

let badStart = """
    one
    two
    """
let end = """
    three
    """
print(badStart + end)
// Prints two lines:
// one
// twothree

let goodStart = """
    one
    two

    """
print(goodStart + end)
// Prints three lines:
// one
// two
// three

上のコードでは、badStartendを連結すると2行の文字列が生成され、これは望ましい結果ではありません。badStartの最後の行が改行で終わっていないため、その行はendの最初の行と結合されます。対照的に、goodStartの両方の行は改行で終わるため、endと結合すると結果は期待どおり3行になります。

文字列補間

文字列補間は、定数、変数、リテラル、式の値を文字列リテラル内に含めることで、それらの組み合わせから新しい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の値が\(multiplier)として文字列リテラルに挿入されています。このプレースホルダーは、文字列補間が評価されて実際の文字列が作成されるときに、multiplierの実際の値に置き換えられます。

multiplierの値は、文字列の後半にあるより大きな式の一部でもあります。この式はDouble(multiplier) * 2.5の値を計算し、結果(7.5)を文字列に挿入します。この場合、式は文字列リテラル内に含まれるときに\(Double(multiplier) * 2.5)と記述されます。

拡張文字列デリミタを使用して、文字列補間として扱われる文字を含む文字列を作成できます。例えば:

print(#"Write an interpolated string in Swift using \(multiplier)."#)
// Prints "Write an interpolated string in Swift using \(multiplier)."

拡張デリミタを使用する文字列内で文字列補間を使用するには、バックスラッシュの後のナンバーサインの数を文字列の先頭と末尾のナンバーサインの数と一致させます。例えば:

print(#"6 times 7 is \#(6 * 7)."#)
// Prints "6 times 7 is 42."

Note 補間された文字列内の括弧内に記述する式には、エスケープされていないバックスラッシュ(\)、キャリッジリターン、または改行を含めることはできません。ただし、他の文字列リテラルを含めることはできます。

Unicode

Unicodeは、異なる書記体系でテキストをエンコード、表現、処理するための国際標準です。ほぼすべての言語のほぼすべての文字を標準化された形式で表現し、テキストファイルやWebページなどの外部ソースからそれらの文字を読み書きすることができます。このセクションで説明するように、SwiftのString型とCharacter型は完全にUnicode準拠です。

Unicodeスカラー値

舞台裏では、SwiftのネイティブString型はUnicodeスカラー値から構築されています。Unicodeスカラー値は、文字または修飾子のための一意の21ビット数値です。例えば、U+0061LATIN SMALL LETTER A"a")、U+1F425FRONT-FACING BABY CHICK"🐥")です。

すべての21ビットUnicodeスカラー値が文字に割り当てられているわけではないことに注意してください。一部のスカラーは将来の割り当てのため、またはUTF-16エンコーディングで使用するために予約されています。文字に割り当てられたスカラー値には通常、上記の例のLATIN SMALL LETTER AFRONT-FACING BABY CHICKのような名前も付いています。

拡張書記素クラスタ

SwiftのCharacter型のすべてのインスタンスは、単一の拡張書記素クラスタを表します。拡張書記素クラスタは、(組み合わされると)単一の人間が読める文字を生成する1つ以上のUnicodeスカラーのシーケンスです。

ここに例があります。文字éは、単一のUnicodeスカラーéLATIN SMALL LETTER E WITH ACUTE、またはU+00E9)として表すことができます。ただし、同じ文字はスカラーのペアとして表すこともできます。標準の文字eLATIN SMALL LETTER E、またはU+0065)の後にCOMBINING ACUTE ACCENTスカラー(U+0301)が続きます。COMBINING ACUTE ACCENTスカラーは、その前のスカラーにグラフィカルに適用され、Unicode対応のテキストレンダリングシステムによってレンダリングされるときにeéに変えます。

どちらの場合も、文字éは拡張書記素クラスタを表す単一のSwift Character値として表されます。最初のケースでは、クラスタには単一のスカラーが含まれています。2番目のケースでは、2つのスカラーのクラスタです:

let eAcute: Character = "\u{E9}"                         // é
let combinedEAcute: Character = "\u{65}\u{301}"          // e followed by ́
// eAcute is é, combinedEAcute is é

拡張書記素クラスタは、多くの複雑なスクリプト文字を単一のCharacter値として表す柔軟な方法です。例えば、韓国語アルファベットのハングル音節は、合成済みまたは分解済みのシーケンスとして表すことができます。これらの表現はどちらもSwiftで単一のCharacter値として認定されます:

let precomposed: Character = "\u{D55C}"                  // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한

拡張書記素クラスタにより、囲みマーク用のスカラー(COMBINING ENCLOSING CIRCLE、またはU+20DDなど)が、単一のCharacter値の一部として他のUnicodeスカラーを囲むことができます:

let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute is é⃝

地域インジケーターシンボル用のUnicodeスカラーをペアで組み合わせて、単一のCharacter値を作成できます。例えば、REGIONAL INDICATOR SYMBOL LETTER UU+1F1FA)とREGIONAL INDICATOR SYMBOL LETTER SU+1F1F8)の組み合わせです:

let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS is 🇺🇸

文字のカウント

文字列内のCharacter値の数を取得するには、文字列のcountプロパティを使用します:

let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// Prints "unusualMenagerie has 40 characters".

SwiftがCharacter値に拡張書記素クラスタを使用しているため、文字列の連結と変更が必ずしも文字列の文字数に影響するわけではないことに注意してください。

例えば、4文字の単語cafeで新しい文字列を初期化し、文字列の末尾にCOMBINING ACUTE ACCENTU+0301)を追加すると、結果の文字列の文字数は依然として4で、4番目の文字はeではなくéになります:

var word = "cafe"
print("the number of characters in \(word) is \(word.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.count)")
// Prints "the number of characters in café is 4".

Note 拡張書記素クラスタは複数のUnicodeスカラーで構成できます。これは、異なる文字、および同じ文字の異なる表現が、保存に異なる量のメモリを必要とする可能性があることを意味します。このため、Swiftの文字は文字列の表現内で同じ量のメモリを占有しません。結果として、文字列内の文字数は、拡張書記素クラスタの境界を決定するために文字列を反復処理せずに計算することはできません。特に長い文字列値を扱う場合は、countプロパティがその文字列の文字を決定するために文字列全体のUnicodeスカラーを反復処理する必要があることに注意してください。

countプロパティによって返される文字のカウントは、同じ文字を含むNSStringlengthプロパティと常に同じではありません。NSStringの長さは、文字列内のUnicode拡張書記素クラスタの数ではなく、文字列のUTF-16表現内の16ビットコードユニットの数に基づいています。

文字列へのアクセスと変更

メソッドとプロパティを通じて、または添字構文を使用して、文字列にアクセスして変更します。

文字列のインデックス

String値には関連するインデックス型String.Indexがあり、これは文字列内の各Characterの位置に対応します。

上記のように、異なる文字は保存に異なる量のメモリを必要とする可能性があるため、特定の位置にどのCharacterがあるかを判断するには、そのStringの先頭または末尾から各Unicodeスカラーを反復処理する必要があります。このため、Swift文字列は整数値でインデックスを付けることができません。

Stringの最初のCharacterの位置にアクセスするには、startIndexプロパティを使用します。endIndexプロパティは、String内の最後の文字の後の位置です。結果として、endIndexプロパティは文字列の添字の有効な引数ではありません。Stringが空の場合、startIndexendIndexは等しくなります。

Stringindex(before:)およびindex(after:)メソッドを使用して、特定のインデックスの前後のインデックスにアクセスします。特定のインデックスからより遠いインデックスにアクセスするには、これらのメソッドを複数回呼び出す代わりにindex(_:offsetBy:)メソッドを使用できます。

添字構文を使用して、特定のStringインデックスのCharacterにアクセスできます。

let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a

文字列の範囲外のインデックスまたは文字列の範囲外のインデックスのCharacterにアクセスしようとすると、ランタイムエラーが発生します。

greeting[greeting.endIndex] // Error
greeting.index(after: greeting.endIndex) // Error

文字列内の個々の文字のすべてのインデックスにアクセスするには、indicesプロパティを使用します。

for index in greeting.indices {
    print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n   T a g ! ".

Note Collectionプロトコルに準拠する任意の型で、startIndexおよびendIndexプロパティとindex(before:)index(after:)、およびindex(_:offsetBy:)メソッドを使用できます。これには、ここで示すStringだけでなく、ArrayDictionarySetなどのコレクション型も含まれます。

挿入と削除

指定されたインデックスで文字列に単一の文字を挿入するには、insert(_:at:)メソッドを使用し、指定されたインデックスで別の文字列の内容を挿入するには、insert(contentsOf:at:)メソッドを使用します。

var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"

welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"

指定されたインデックスで文字列から単一の文字を削除するには、remove(at:)メソッドを使用し、指定された範囲の部分文字列を削除するには、removeSubrange(_:)メソッドを使用します:

welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"

let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"

Note RangeReplaceableCollectionプロトコルに準拠する任意の型で、insert(_:at:)insert(contentsOf:at:)remove(at:)、およびremoveSubrange(_:)メソッドを使用できます。これには、ここで示すStringだけでなく、ArrayDictionarySetなどのコレクション型も含まれます。

部分文字列

文字列から部分文字列を取得する場合(例えば、添字やprefix(_:)のようなメソッドを使用して)、結果は別の文字列ではなくSubstringのインスタンスです。Swiftの部分文字列は文字列とほとんど同じメソッドを持っているため、文字列と同じ方法で部分文字列を操作できます。ただし、文字列とは異なり、部分文字列は文字列に対するアクションを実行している短い時間だけ使用します。結果をより長い時間保存する準備ができたら、部分文字列をStringのインスタンスに変換します。例えば:

let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"

// Convert the result to a String for long-term storage.
let newString = String(beginning)

文字列と同様に、各部分文字列には、部分文字列を構成する文字が格納されるメモリ領域があります。文字列と部分文字列の違いは、パフォーマンスの最適化として、部分文字列は元の文字列の保存に使用されるメモリの一部、または別の部分文字列の保存に使用されるメモリの一部を再利用できることです。(文字列にも同様の最適化がありますが、2つの文字列がメモリを共有する場合、それらは等しいです。)このパフォーマンス最適化により、文字列または部分文字列を変更するまでメモリをコピーするパフォーマンスコストを支払う必要がありません。上記のように、部分文字列は元の文字列のストレージを再利用するため、長期保存には適していません。部分文字列のいずれかが使用されている限り、元の文字列全体をメモリに保持する必要があります。

上の例では、greetingは文字列であり、文字列を構成する文字が格納されるメモリ領域を持っています。beginninggreetingの部分文字列であるため、greetingが使用するメモリを再利用します。対照的に、newStringは文字列です。部分文字列から作成されると、独自のストレージを持ちます。以下の図はこれらの関係を示しています:

stringSubstring

Note StringSubstringはどちらもStringProtocolプロトコルに準拠しているため、文字列操作関数がStringProtocol値を受け入れることが便利なことがよくあります。そのような関数はStringまたはSubstring値のいずれかで呼び出すことができます。

文字列の比較

Swiftは、テキスト値を比較する3つの方法を提供します:文字列と文字の等価性、接頭辞の等価性、および接尾辞の等価性。

文字列と文字の等価性

文字列と文字の等価性は、比較演算子で説明されているように、「等しい」演算子(==)と「等しくない」演算子(!=)でチェックされます:

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つのString値(または2つのCharacter値)は等しいと見なされます。拡張書記素クラスタは、舞台裏では異なるUnicodeスカラーで構成されていても、同じ言語的意味と外観を持っていれば正準等価です。

例えば、LATIN SMALL LETTER E WITH ACUTEU+00E9)は、LATIN SMALL LETTER EU+0065)の後にCOMBINING ACUTE ACCENTU+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 AU+0041、または"A")は、ロシア語で使用されるCYRILLIC CAPITAL LETTER AU+0410、または"А")と同等ではありません。文字は視覚的に似ていますが、同じ言語的意味を持っていません:

let latinCapitalLetterA: Character = "\u{41}"

let cyrillicCapitalLetterA: Character = "\u{0410}"

if latinCapitalLetterA != cyrillicCapitalLetterA {
    print("These two characters aren't equivalent.")
}
// Prints "These two characters aren't equivalent."

Note Swiftの文字列と文字の比較はロケールに依存しません。

接頭辞と接尾辞の等価性

文字列が特定の文字列接頭辞または接尾辞を持っているかどうかを確認するには、文字列のhasPrefix(_:)およびhasSuffix(_:)メソッドを呼び出します。どちらもString型の単一の引数を取り、ブール値を返します。

以下の例は、シェイクスピアのロミオとジュリエットの最初の2幕のシーンの場所を表す文字列の配列を考慮しています:

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"
]

romeoAndJuliet配列でhasPrefix(_:)メソッドを使用して、劇の第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(_:)メソッドを使用して、キャピュレット邸やロレンス修道士の庵室の中または周辺で行われるシーンの数をカウントします:

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(_:)メソッドは、文字列と文字の等価性で説明されているように、各文字列の拡張書記素クラスタ間の文字ごとの正準等価比較を実行します。

文字列のUnicode表現

Unicode文字列がテキストファイルやその他のストレージに書き込まれる場合、その文字列内のUnicodeスカラーは、Unicodeで定義されたいくつかのエンコーディング形式のいずれかでエンコードされます。各形式は、コードユニットと呼ばれる小さなチャンクで文字列をエンコードします。これには、UTF-8エンコーディング形式(8ビットコードユニットとして文字列をエンコード)、UTF-16エンコーディング形式(16ビットコードユニットとして文字列をエンコード)、およびUTF-32エンコーディング形式(32ビットコードユニットとして文字列をエンコード)が含まれます。

Swiftは、文字列のUnicode表現にアクセスするためのいくつかの異なる方法を提供します。for-inステートメントで文字列を反復処理して、Unicode拡張書記素クラスタとして個々のCharacter値にアクセスできます。このプロセスについては文字の操作で説明しています。

あるいは、他の3つのUnicode準拠の表現のいずれかでString値にアクセスします:

  • UTF-8コードユニットのコレクション(文字列のutf8プロパティでアクセス)
  • UTF-16コードユニットのコレクション(文字列のutf16プロパティでアクセス)
  • 21ビットUnicodeスカラー値のコレクション、文字列のUTF-32エンコーディング形式と同等(文字列のunicodeScalarsプロパティでアクセス)

以下の各例は、文字DogDOUBLE EXCLAMATION MARK、またはUnicodeスカラーU+203C)、および🐶文字(DOG FACE、またはUnicodeスカラーU+1F436)で構成される以下の文字列の異なる表現を示しています:

let dogString = "Dog‼🐶"

UTF-8表現

StringのUTF-8表現には、そのutf8プロパティを反復処理することでアクセスできます。このプロパティはString.UTF8View型で、文字列のUTF-8表現の各バイトに対して1つずつ、符号なし8ビット(UInt8)値のコレクションです:

UTF8

for codeUnit in dogString.utf8 {
    print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 226 128 188 240 159 144 182 ".

上の例では、最初の3つの10進数codeUnit値(68111103)は文字Dogを表しており、そのUTF-8表現はASCII表現と同じです。次の3つの10進数codeUnit値(226128188)は、DOUBLE EXCLAMATION MARK文字の3バイトUTF-8表現です。最後の4つのcodeUnit値(240159144182)は、DOG FACE文字の4バイトUTF-8表現です。

UTF-16表現

StringのUTF-16表現には、そのutf16プロパティを反復処理することでアクセスできます。このプロパティはString.UTF16View型で、文字列のUTF-16表現の各16ビットコードユニットに対して1つずつ、符号なし16ビット(UInt16)値のコレクションです:

UTF16

for codeUnit in dogString.utf16 {
    print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 55357 56374 ".

繰り返しますが、最初の3つのcodeUnit値(68111103)は文字Dogを表しており、そのUTF-16コードユニットは文字列のUTF-8表現と同じ値を持っています(これらのUnicodeスカラーはASCII文字を表すため)。

4番目のcodeUnit値(8252)は、16進数値203Cの10進数相当であり、DOUBLE EXCLAMATION MARK文字のUnicodeスカラーU+203Cを表しています。この文字はUTF-16で単一のコードユニットとして表すことができます。

5番目と6番目のcodeUnit値(5535756374)は、DOG FACE文字のUTF-16サロゲートペア表現です。これらの値は、U+D83D(10進数値55357)の高サロゲート値とU+DC36(10進数値56374)の低サロゲート値です。

Unicodeスカラー表現

String値のUnicodeスカラー表現には、そのunicodeScalarsプロパティを反復処理することでアクセスできます。このプロパティはUnicodeScalarView型で、UnicodeScalar型の値のコレクションです。

UnicodeScalarには、UInt32値内で表されるスカラーの21ビット値を返すvalueプロパティがあります:

UnicodeScalar

for scalar in dogString.unicodeScalars {
    print("\(scalar.value) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 128054 ".

最初の3つのUnicodeScalar値のvalueプロパティ(68111103)は再び文字Dogを表しています。

4番目のcodeUnit値(8252)も再び16進数値203Cの10進数相当であり、DOUBLE EXCLAMATION MARK文字のUnicodeスカラーU+203Cを表しています。

5番目で最後のUnicodeScalarvalueプロパティ128054は、16進数値1F436の10進数相当であり、DOG FACE文字のUnicodeスカラーU+1F436を表しています。

valueプロパティをクエリする代わりに、各UnicodeScalar値を使用して、文字列補間などで新しいString値を構築することもできます:

for scalar in dogString.unicodeScalars {
    print("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶