String
имеет ассоциированный тип индекса - String.Index
, который связан с позицией каждого Character
в строке.
String
. По этой причине Swift строки не могут быть проиндексированы целыми числами.
startIndex
для доступа к позиции первого Character
в String
. Свойство endIndex
- это позиция после последнего Character
в String
. В результате свойство endIndex
не является корректным аргументом для сабскрипта/ строки. Если String
пуста, то startIndex
и endIndex
равны.
index(before:)
и index(after:)
. Для доступа к индексу на расстоянии от заданного индекса Вы можете использовать метод index(_:offsetBy:)
вместо вызова одного из ранее описанных методов несколько раз.
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
на позиции за границами интервала строки вызовет ошибку времени выполнения.
let greeting = "Guten Tag!"
greeting[greeting.endIndex] // Ошибка
greeting.index(after: greeting.endIndex) // Ошибка
indices
для доступа ко всем индексам отдельных символов в строке:
startIndex
и endIndex
, ровно как и методы index(before:)
, index(after:)
и index(_:offsetBy:)
на любом типе, который удовлетворяет протоколу Collection
. Это подразумевает под собой String
, а также типы коллекций как Array
, Dictionary
и Set
.
let greeting = "Guten Tag!"
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: " ")
}
// Напечатает "G u t e n T a g !"
insert(_:at:)
и для вставки контента другой строки на специальную позицию используйте метод insert(contentsOf:at:)
.
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome теперь равен "hello!"
welcome.insert(contentsOf:" there".characters, at: welcome.index(before: welcome.endIndex))
// welcome теперь равен "hello there!”
remove(at:)
и для удаления подстроки в конкретном диапазоне Вы можете использовать метод removeSubrange(_:)
:
var welcome = "hello there!"
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome теперь равно "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<
welcome.endIndex
welcome.removeSubrange(range)
// welcome теперь равно "hello”
insert(_:at:)
, insert(contentsOf:at:)
, remove(at:)
и removeSubrange(_:)
на любом типе, который удовлетворяет протоколу Collection
. Это подразумевает под собой String
, а также типы коллекций как Array
, Dictionary
и Set
.
prefix(_:)
, - результат будет экземпляром Substring
, а не другой строкой. Подстроки в Swift в основном имеют те же методы, что и строки: Вы можете использовать подстроки как строки. В отличие от строк Вы можете использовать подстроки только на короткое время в процессе выполнения действий над строками. Когда Вы будете готовы сохранить результат на большее время, Вы должны конвертировать подстроки в экземпляр типа String
. Например:
let greeting = "Hello, world!"
let index = greeting.index(of: ",") ?? greeting.endIndex
let beginning = greeting[..< index]
// beginning равен "Hello"
//Преобразуйте результат в String на долгосрочное хранение.
let newString = String(beginning)
String
, и Substring
удовлетворяют протоколу StringProtocol
. Если Вы пишите код, который манипулирует строковыми данными, применение значения типа StringProtocol
позволит Вам передавать строковые данные в качестве String
или Substring
.
greeting
- это строка, что значит, что она имеет участок памяти, где хранятся символы, образующие строки. Так как begining
- это подстрока greeting
, то она реиспользует память greeting
. Напротив, newString
- это строка: когда она создана из подстроки, она будет иметь своё собственное хранилище. Рисунок ниже демонстрирует эти отношения.
let quotation = "Мы ведь так похожи, Ты и я."
let sameQuotation = "Мы ведь так похожи, Ты и я."
if quotation == sameQuotation {
print("Эти две строки считаются эквивалентными.")
}
// Выведет "Эти две строки считаются эквивалентными."
String
(или Character
) считаются равными, если их расширенные графем-кластеры канонично эквивалентны. Расширенные графем-кластеры канонично эквиваленты, если они имеют одинаковые лингвистические значение и вид, даже если они составлены из разных Юникод-скаляров за кулисами.
// "Voulez-vous un café?" использует LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
// "Voulez-vous un café?" использует LATIN SMALL LETTER E и COMBINING ACUTE ACCENT
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
if eAcuteQuestion == combinedEAcuteQuestion {
print("Эти две строки считаются эквивалентными.")
}
// Выведет "Эти две строки считаются эквивалентными."
Например, LATIN SMALL LETTER E WITH ACUTE (U+00E9) канонично эквивалентен LATIN SMALL LETTER E (U+0065), дополненному COMBINING ACUTE ACCENT (U+0301). Оба этих расширенных графем-кластера - корректные способы для представления символа é, так что они канонично эквивалентны.
let latinCapitalLetterA: Character = "\u{41}"
let cyrillicCapitalLetterA: Character = "\u{0410}"
if latinCapitalLetterA != cyrillicCapitalLetterA {
print("Эти строки считаются не равными")
}
// Выведет "Эти строки считаются не равными"
Обратно, LATIN CAPITAL LETTER A (U+0041 или "A"), используемая в Английском, не эквивалентна CYRILLIC CAPITAL LETTER A (U+0410 или "А"), используемой в Русском. Эти символы визуально одинаковы, но не имеют одинакового лингвистического значения.
hasPrefix(_:)
или hasSuffix(_:)
, каждый из которых принимает один аргумент типа String
и возвращает Булево значение.
hasPrefix(_:)
и hasSuffix(_:)
осуществляют посимвольное канонично эквивалентное сравнение между расширенными графем-кластерами.
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"
]
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
act1SceneCount += 1
}
}
print("Есть \(act1SceneCount) сцен в акте 1")
// Выведет "Есть 5 сцен в акте 1"
Вы можете использовать метод hasPrefix(_:)
с массивом romeoAndJuliet
для подсчёта количества сцен в первом акте пьесы.
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) сцен в особняке; \(cellCount) сцены в камере")
// Выводит "6 сцен в особняке; 2 сцены в камере"
Аналогично Вы можете использовать метод hasSuffix(_:)
для подсчёта количества сцен, которые происходят внутри или вокруг особняка Капулетти и клетки монаха Лоренцо.