Spec-Zone.ru › Swift Language

Строки и символы

Хранение и обработка текста.

Строка — это последовательность символов, например, "hello, world" или "albatross". В Swift строки представлены типом String. Содержимое строки String можно получить различными способами, включая представление в виде набора значений Character.

Типы String и Character Swift предоставляют быстрый и совместимый с Unicode способ работы с текстом в коде. Синтаксис создания и обработки строк легкий и читабельный, с синтаксисом строковых литералов, похожим на C. Конкатенация строк — это просто объединение двух строк с оператором +, а неизменяемость строк управляется выбором между константой и переменной, как и любое другое значение в Swift. Вы также можете использовать строки для вставки констант, переменных, литералов и выражений в более длинные строки, в процессе, известном как интерполяция строк. Это упрощает создание пользовательских строковых значений для отображения, хранения и вывода.

Несмотря на эту простоту синтаксиса, тип String Swift представляет собой быструю современную реализацию строк. Каждая строка состоит из независимых от кодировки символов Unicode и предоставляет поддержку доступа к этим символам в различных представлениях Unicode.

Примечание: тип String Swift связан с классом NSString Foundation. Foundation также расширяет String, чтобы экспонировать методы, определённые NSString. Это означает, что если вы импортируете Foundation, вы можете получить доступ к этим методам NSString для String без приведения типов.

Дополнительную информацию об использовании String с Foundation и Cocoa см. в Связывание между String и NSString.

Строковые литералы

Вы можете включать предопределённые String значения в свой код в виде строковых литералов. Строковый литерал — это последовательность символов, заключённых в двойные кавычки (").

Используйте строковый литерал в качестве начального значения для константы или переменной:

let someString = "Some string literal value"

Обратите внимание, что Swift определяет тип String для константы someString, потому что она инициализирована строковым литералом.

Многострочные строковые литералы

Если вам нужна строка, занимающая несколько строк, используйте многострочный строковый литерал — последовательность символов, заключённых в три двойные кавычки:

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, какие пробелы игнорировать перед всеми другими строками. Однако, если вы напишете пробелы в начале строки, помимо пробелов перед закрывающей кавычкой, эти пробелы будут включены.

В приведённом выше примере, даже если весь многострочный строковый литерал отступает, первая и последняя строки в строке не начинаются с пробелов. Средняя строка имеет больший отступ, чем закрывающие кавычки, поэтому она начинается с дополнительного отступа в четыре пробела.

Специальные символы в строковых литералах

Строковые литералы могут включать следующие специальные символы:

  • Экранированные специальные символы \0 (символ null), \\ (обратная косая черта), \t (горизонтальная табуляция), \n (перевод строки), \r (возврат каретки), \" (двойная кавычка) и \' (одинарная кавычка)
  • Произвольное значение скаляра Unicode, написанное как \u{n}, где n — 1–8-значное шестнадцатеричное число (Unicode обсуждается в <doc:StringsAndCharacters#Unicode> ниже)

Ниже приведён код с четырьмя примерами этих специальных символов. Константа wiseWords содержит две экранированные двойные кавычки. Константы dollarSign, blackHeart и sparklingHeart демонстрируют формат скаляра 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

Поскольку многострочные строковые литералы используют три двойные кавычки вместо одной, вы можете включить двойную кавычку (") внутри многострочного строкового литерала без экранирования. Чтобы включить текст """ в многострочную строку, экранируйте хотя бы одну из кавычек. Например:

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

Расширенные разделители строк

Вы можете поместить строковый литерал в расширенные разделители, чтобы включить специальные символы в строку без вызова их эффекта. Вы помещаете строку в кавычки (") и окружаете её символами решётки (#). Например, вывод строкового литерала #"Line 1\nLine 2"# выводит последовательность escape-символа новой строки (\n), а не выводит строку на двух строках.

Если вам нужен специальный эффект символа в строковом литерале, согласуйте количество символов решётки в строке после escape-символа (\). Например, если ваша строка — #"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

Примечание: Этот подход отличается от изменения строк в Objective-C и Cocoa, где вы выбираете между двумя классами (NSString и NSMutableString), чтобы указать, может ли строка быть изменена.

Строки — это типы значений

Тип String Swift является типом значения. Если вы создаёте новое значение String, это значение String копируется, когда оно передаётся в функцию или метод, или когда оно присваивается константе или переменной. В каждом случае создаётся новая копия существующего значения String, и новая копия передаётся или присваивается, а не исходная версия. Типы значений описаны в <doc:ClassesAndStructures#Structures-and-Enumerations-Are-Value-Types>.

Поведение копирования по умолчанию для String Swift гарантирует, что когда функция или метод передают вам значение String, вам ясно, что вы владеете этим точным значением String, независимо от источника. Вы можете быть уверены, что строка, которая вам передаётся, не будет изменена, если вы сами не измените её.

Под капотом компилятор Swift оптимизирует использование строк таким образом, что фактическое копирование происходит только при необходимости. Это означает, что вы всегда получаете отличную производительность при работе со строками как с типами значений.

Работа с символами

Вы можете получить доступ к отдельным значениям Character для String, перебирая строку с помощью цикла for-in:

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

Цикл for-in описан в <doc:ControlFlow#For-In-Loops>.

В качестве альтернативы вы можете создать отдельную константу или переменную 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"

Вы можете добавить значение Character к переменной String с методом типа String append():

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

Примечание: Вы не можете добавить значение String или Character к существующей переменной 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

В коде выше, конкатенация badStart с end создаёт строку из двух строк, что не является желаемым результатом. Поскольку последняя строка badStart не заканчивается переводом строки, эта строка объединяется с первой строкой end. В отличие от этого, обе строки goodStart заканчиваются переводом строки, поэтому, когда они объединяются с end, результат имеет три строки, как и ожидалось.

Интерполяция строк

Интерполяция строк — это способ построения нового 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."

Примечание: выражения, которые вы пишете в скобках внутри интерполированной строки, не могут содержать неэкранированную обратную косую черту (\), возврат каретки или перевод строки. Однако они могут содержать другие строковые литералы.

Unicode

Unicode — это международный стандарт для кодирования, представления и обработки текста в разных письменных системах. Он позволяет представлять практически любой символ из любого языка в стандартизированной форме и читать/записывать эти символы из/в внешнего источника, такого как текстовый файл или веб-страница. Swift’s String и Character типы полностью соответствуют Unicode, как описано в этом разделе.

Значения скаляров Unicode

За кулисами, родной тип Swift String построен из значений скаляров Unicode. Значение скаляра Unicode — это уникальное 21-битное число для символа или модификатора, например, U+0061 для LATIN SMALL LETTER A ("a") или U+1F425 для FRONT-FACING BABY CHICK ("🐥").

Обратите внимание, что не все 21-битные значения скаляров Unicode назначены символам — некоторые скаляры зарезервированы для будущего назначения или для использования в кодировании UTF-16. Значения скаляров, которые были назначены символу, обычно также имеют имя, такие как LATIN SMALL LETTER A и FRONT-FACING BABY CHICK в примерах выше.

Расширенные кластеры графем

Каждый экземпляр типа Swift Character представляет собой один расширенный кластер графем. Расширенный кластер графем — это последовательность одного или нескольких значений скаляров Unicode, которые (в совокупности) образуют один читаемый человеком символ.

Вот пример. Буква é может быть представлена ​​одним значением скаляра Unicode é (LATIN SMALL LETTER E WITH ACUTE или U+00E9). Однако та же буква может быть представлена ​​также парой скаляров — стандартной буквой e (LATIN SMALL LETTER E или U+0065), за которой следует скаляр COMBINING ACUTE ACCENT (U+0301). Скаляр COMBINING ACUTE ACCENT графически применяется к скаляру, который предшествует ему, превращая e в é при отображении системой рендеринга текста, поддерживающей Unicode.

В обоих случаях буква é представлена как одно значение Swift Character, которое представляет расширенный кластер графем. В первом случае кластер содержит один скаляр, во втором — кластер из двух скаляров:

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

Расширенные кластеры графем — гибкий способ представления многих сложных символов скриптов как одного значения Character. Например, слоги хангул из корейского алфавита могут быть представлены как прекомпонованной, так и декомпонованной последовательностью. Оба эти представления соответствуют одному значению Character в Swift:

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

Расширенные кластеры графем позволяют использовать скаляры для заключённых знаков (такие как COMBINING ENCLOSING CIRCLE или U+20DD) для заключения других скаляров Unicode как части одного значения Character:

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

Скаляры Unicode для региональных индикаторных символов могут быть объединены парами, чтобы образовать одно значение Character, например, это сочетание REGIONAL INDICATOR SYMBOL LETTER U (U+1F1FA) и REGIONAL INDICATOR SYMBOL LETTER S (U+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 означает, что конкатенация и модификация строк могут не всегда влиять на количество символов в строке.

Например, если вы инициализируете новую строку четырёхсимвольным словом cafe, а затем добавляете COMBINING ACUTE ACCENT (U+0301) в конец строки, результирующая строка по-прежнему будет иметь количество символов 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"

Примечание: Расширенные кластеры графем могут состоять из нескольких значений скаляров Unicode. Это означает, что разные символы — и разные представления одного и того же символа — могут требовать различного объёма памяти для хранения. Из-за этого символы в Swift не занимают одинаковое количество памяти в представлении строки. В результате количество символов в строке нельзя вычислить без итерации по строке для определения границ расширенных кластеров графем. Если вы работаете со значениями строк, особенно большой длины, имейте в виду, что свойство count должно итерироваться по значениям скаляров Unicode во всей строке, чтобы определить символы для этой строки.

Количество символов, возвращаемое свойством count, не всегда совпадает со свойством length NSString, содержащей те же символы. Длина NSString основана на количестве 16-битных кодовых единиц в представлении строки UTF-16, а не на количестве расширенных кластеров графем в строке.

Доступ к строке и её модификация

Вы получаете доступ к строке и изменяете её через её методы и свойства или с помощью синтаксиса индексации.

Индексы строк

Каждое значение String имеет связанный тип индекса, String.Index, который соответствует положению каждого Character в строке.

Как упоминалось выше, разные символы могут требовать разного объёма памяти для хранения, поэтому для определения того, какой Character находится в определённой позиции, необходимо итерироваться по каждому значению скаляра Unicode с начала или конца этой String. По этой причине строкам Swift нельзя индексировать с помощью целочисленных значений.

Используйте свойство startIndex для доступа к положению первого Character в String. Свойство endIndex — это позиция после последнего символа в String. В результате свойство endIndex не является допустимым аргументом для индексации строки.

Если String пуста, свойства startIndex и endIndex равны.

Вы получаете доступ к индексам до и после заданного индекса с помощью методов index(before:) и index(after:) типа String. Для доступа к индексу, более удалённому от заданного индекса, можно использовать метод index(_:offsetBy:) вместо многократного вызова этих методов.

Вы можете использовать синтаксис индексации для доступа к Character по определённому индексу String.

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

Примечание: Вы можете использовать свойства startIndex и endIndex и методы index(before:), index(after:) и index(_:offsetBy:) для любого типа, соответствующего протоколу Collection. Это включает в себя String, как показано здесь, а также типы коллекций, такие как Array, Dictionary и Set.

Вставка и удаление

Для вставки одного символа в строку по заданному индексу используйте метод 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"

Примечание: Вы можете использовать методы insert(_:at:), insert(contentsOf:at:), remove(at:) и removeSubrange(_:) для любого типа, соответствующего протоколу RangeReplaceableCollection. Это включает в себя String, как показано здесь, а также типы коллекций, такие как Array, Dictionary и Set.

Подстроки

Когда вы получаете подстроку из строки — например, используя индексацию или метод, такой как 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)

Как и строки, каждый подстрочный фрагмент имеет область памяти, где хранятся символы, составляющие подстрочный фрагмент. Разница между строками и подстрочными фрагментами заключается в том, что в целях повышения производительности подстрочный фрагмент может повторно использовать часть памяти, используемой для хранения исходной строки, или часть памяти, используемой для хранения другого подстрочного фрагмента. (Строки имеют аналогичную оптимизацию, но если две строки разделяют память, они равны). Эта оптимизация производительности означает, что вам не нужно платить за стоимость копирования памяти до тех пор, пока вы не измените строку или подстрочный фрагмент. Как упоминалось выше, подстрочные фрагменты не подходят для долгосрочного хранения — поскольку они повторно используют хранилище исходной строки, вся исходная строка должна храниться в памяти, пока используются какие-либо её подстрочные фрагменты.

В приведенном выше примере greeting — это строка, что означает, что она имеет область памяти, где хранятся символы, составляющие строку. Поскольку beginning является подстрочным фрагментом greeting, он повторно использует память, используемую greeting. В противоположность этому, newString — это строка; при создании из подстрочного фрагмента она имеет собственное хранилище. На рисунке ниже показаны эти отношения:

Примечание: и String, и Substring соответствуют протоколу StringProtocol, что делает удобным для функций манипулирования строками прием значения StringProtocol. Вы можете вызывать такие функции, используя либо значение String, либо Substring.

Сравнение строк

Swift предоставляет три способа сравнения текстовых значений: равенство строк и символов, равенство префиксов и равенство суффиксов.

Равенство строк и символов

Равенство строк и символов проверяется оператором «равно» (==) и оператором «не равно» (!=), как описано в <doc:BasicOperators#Comparison-Operators>:

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"

Два значения String (или два значения Character) считаются равными, если их расширенные графемные кластеры канонически эквивалентны. Расширенные графемные кластеры канонически эквивалентны, если они имеют одинаковый лингвистический смысл и внешний вид, даже если они составлены из разных скаляров Юникода за кулисами.

Например, 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 или "A"), используемое в английском языке, не эквивалентно CYRILLIC CAPITAL LETTER A (U+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."

Примечание: сравнения строк и символов в Swift не зависят от локали.

Равенство префиксов и суффиксов

Чтобы проверить, содержит ли строка определенный префикс или суффикс, вызовите методы hasPrefix(_:) и hasSuffix(_:) строки, оба принимающие один аргумент типа String и возвращающие булево значение.

В примерах ниже рассматривается массив строк, представляющих места действия из первых двух актов «Ромео и Джульетта» Шекспира:

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(_:) с массивом romeoAndJuliet, чтобы подсчитать количество сцен в Акте 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"

Примечание: методы hasPrefix(_:) и hasSuffix(_:) выполняют сравнение канонической эквивалентности символ за символом расширенных графемных кластеров в каждой строке, как описано в <doc:StringsAndCharacters#String-and-Character-Equality>.

Представления строк в Юникоде

Когда строка Юникода записывается в текстовый файл или в какое-либо другое хранилище, скаляры Юникода в этой строке кодируются в одной из нескольких форм кодирования Юникода. Каждая форма кодирует строку небольшими блоками, известными как единицы кода. К ним относятся форма кодирования UTF-8 (кодирующая строку как 8-битные единицы кода), форма кодирования UTF-16 (кодирующая строку как 16-битные единицы кода) и форма кодирования UTF-32 (кодирующая строку как 32-битные единицы кода).

Swift предоставляет несколько способов доступа к представлениям строк в Юникоде. Вы можете перебирать строку с помощью цикла for-in, чтобы получить доступ к её отдельным значениям Character в качестве расширенных графемных кластеров Юникода. Этот процесс описан в <doc:StringsAndCharacters#Working-with-Characters>.

В качестве альтернативы, вы можете получить доступ к значению String в одном из трёх других совместимых с Юникодом представлений:

  • Коллекция единиц кода UTF-8 (доступ к ней осуществляется с помощью свойства utf8 строки)
  • Коллекция единиц кода UTF-16 (доступ к ней осуществляется с помощью свойства utf16 строки)
  • Коллекция значений скаляров Юникода с 21-битным разрядом, эквивалентная форме кодирования UTF-32 строки (доступ к ней осуществляется с помощью свойства unicodeScalars строки)

Каждый пример ниже демонстрирует разное представление следующей строки, состоящей из символов D, o, g, ‼ (DOUBLE EXCLAMATION MARK или скаляр Юникода U+203C), и символа 🐶 (DOG FACE или скаляр Юникода U+1F436):

let dogString = "Dog‼🐶"

Представление UTF-8

Вы можете получить доступ к представлению UTF-8 строки, перебирая её свойство utf8. Это свойство имеет тип String.UTF8View, являющееся коллекцией беззнаковых 8-битных (UInt8) значений, по одному для каждого байта в представлении строки UTF-8:

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

В примере выше первые три десятичных значения codeUnit (68, 111, 103) представляют символы D, o и g, чьё представление UTF-8 совпадает с их представлением ASCII. Следующие три десятичных значения codeUnit (226, 128, 188) являются трёхбайтовым представлением UTF-8 символа DOUBLE EXCLAMATION MARK. Последние четыре значения codeUnit (240, 159, 144, 182) — четырёхбайтовым представлением UTF-8 символа DOG FACE.

Представление UTF-16

Вы можете получить доступ к представлению UTF-16 строки, перебирая её свойство utf16. Это свойство имеет тип String.UTF16View, являющееся коллекцией беззнаковых 16-битных (UInt16) значений, по одному для каждой 16-битной единицы кода в представлении строки UTF-16:

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

Опять же, первые три значения codeUnit (68, 111, 103) представляют символы D, o и g, чьи единицы кода UTF-16 имеют те же значения, что и в представлении UTF-8 (потому что эти скаляры Юникода представляют символы ASCII).

Четвёртое значение codeUnit (8252) является десятичным эквивалентом шестнадцатеричного значения 203C, которое представляет скаляр Юникода U+203C для символа DOUBLE EXCLAMATION MARK. Этот символ может быть представлен одной единицей кода в UTF-16.

Пятое и шестое значения codeUnit (55357 и 56374) — представлением пары суррогатных символов UTF-16 символа DOG FACE. Эти значения представляют собой старший суррогатный символ U+D83D (десятичное значение 55357) и младший суррогатный символ U+DC36 (десятичное значение 56374).

Представление скаляров Юникода

Вы можете получить доступ к представлению скаляров Юникода значения String, перебирая его свойство unicodeScalars. Это свойство имеет тип UnicodeScalarView, являющееся коллекцией значений типа UnicodeScalar.

Каждое значение UnicodeScalar имеет свойство value, которое возвращает 21-битовое значение скаляра, представленное в значении UInt32:

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

Свойства value для первых трёх значений UnicodeScalar (68, 111, 103) снова представляют символы D, o и g.

Четвёртое значение codeUnit (8252) снова является десятичным эквивалентом шестнадцатеричного значения 203C, представляющего скаляр Юникода U+203C для символа DOUBLE EXCLAMATION MARK.

Свойство value пятого и последнего значения UnicodeScalar, 128054, представляет собой десятичный эквивалент шестнадцатеричного значения 1F436, которое представляет скаляр Юникода U+1F436 для символа DOG FACE.

В качестве альтернативы обращению к их свойствам value, каждое значение UnicodeScalar также может быть использовано для построения нового значения String, например, с помощью интерполяции строк:

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

This source file is part of the Swift.org open source project
Copyright © 2014 - 2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API