Каков самый краткий способ удалить первый символ из строки в Swift?
Я хочу удалить первый символ из строки. До сих пор самая краткая вещь, которую я придумал, это:
display.text = display.text!.substringFromIndex(advance(display.text!.startIndex, 1))
Я знаю, что мы не можем индекса в строку с Int
из-за Unicode, но это решение кажется ужасно многословным. Есть ли другой способ, который я упускаю из виду?
13 ответов:
если вы используете Swift 3, вы можете игнорировать второй раздел этого ответа. Хорошая новость в том, что теперь это на самом деле сжато снова! Просто используя новый метод remove(at:) строки.
var myString = "Hello, World" myString.remove(at: myString.startIndex) myString // "ello, World"
мне нравится глобального
dropFirst()
функция для этого.let original = "Hello" // Hello let sliced = dropFirst(original) // ello
он короткий, ясный и работает для всего, что соответствует протоколу Sliceable.
если вы используете Swift 2 этот ответ был изменен. Вы все еще можете используйте dropFirst, но не без удаления первого символа из ваших строк
characters
свойство, а затем преобразование результата обратно в строку. dropFirst также стал методом, а не функцией.let original = "Hello" // Hello let sliced = String(original.characters.dropFirst()) // ello
Другой альтернативой является использование функции суффикса для соединения строки
UTF16View
. Конечно, это должно быть преобразовано обратно в строку после этого, а также.let original = "Hello" // Hello let sliced = String(suffix(original.utf16, original.utf16.count - 1)) // ello
все это означает, что решение, которое я первоначально предоставил, оказалось не так наиболее лаконичный способ сделать это в новых версиях Swift. Я рекомендую вернуться к решению @chris с помощью
removeAtIndex()
если вы ищете короткое и понятное решение.var original = "Hello" // Hello let removedChar = original.removeAtIndex(original.startIndex) original // ello
и как указано @vacawama в комментариях ниже, другой вариант, который не изменяет исходную строку, - использовать substringFromIndex.
let original = "Hello" // Hello let substring = original.substringFromIndex(advance(original.startIndex, 1)) // ello
или если вы хотите удалить символ из начала и конца строки, вы можете использовать substringWithRange. Просто будьте уверены, чтобы защитить от состояния, когда
startIndex + n > endIndex - m
.let original = "Hello" // Hello let newStartIndex = advance(original.startIndex, 1) let newEndIndex = advance(original.endIndex, -1) let substring = original.substringWithRange(newStartIndex..<newEndIndex) // ell
последняя строка также может быть записана с помощью подстрочной нотации.
let substring = original[newStartIndex..<newEndIndex]
обновление для Swift 4
В Swift 4,
String
соответствуетCollection
опять же, так что можно использоватьdropFirst
иdropLast
обрезать начала и концы строк. Результат имеет типSubstring
, так что вам нужно передать этоString
конструктор, чтобы вернуться вString
:let str = "hello" let result1 = String(str.dropFirst()) // "ello" let result2 = String(str.dropLast()) // "hell"
dropFirst()
иdropLast()
такжеInt
чтобы указать количество символов для удаления:let result3 = String(str.dropLast(3)) // "he" let result4 = String(str.dropFirst(4)) // "o"
если вы укажете больше символы, которые нужно отбросить, чем находятся в строке, результатом будет пустая строка (
""
).let result5 = String(str.dropFirst(10)) // ""
обновление для Swift 3
если вы просто хотите удалить первый символ и хотите изменить исходную строку на месте, то см. ответ @MickMacCallum. Если вы хотите создать новую строку в процессе, использовать
substring(from:)
. С расширением доString
, вы можете скрыть неприглядностьsubstring(from:)
иsubstring(to:)
для создания полезных дополнений обрезать начало и конецString
:extension String { func chopPrefix(_ count: Int = 1) -> String { return substring(from: index(startIndex, offsetBy: count)) } func chopSuffix(_ count: Int = 1) -> String { return substring(to: index(endIndex, offsetBy: -count)) } } "hello".chopPrefix() // "ello" "hello".chopPrefix(3) // "lo" "hello".chopSuffix() // "hell" "hello".chopSuffix(3) // "he"
как
dropFirst
иdropLast
перед ними эти функции будут аварийно завершены, если в строке недостаточно букв. Бремя лежит на вызывающем абоненте, чтобы использовать их должным образом. Это обоснованное проектное решение. Можно было бы написать их, чтобы вернуть необязательный, который затем должен был бы быть развернут вызывающим.
Swift 2.x
увы в Swift 2,
dropFirst
иdropLast
(Предыдущее лучшее решение) не так удобно, как раньше. С расширением доString
, вы можете скрыть неприглядностьsubstringFromIndex
иsubstringToIndex
:extension String { func chopPrefix(count: Int = 1) -> String { return self.substringFromIndex(advance(self.startIndex, count)) } func chopSuffix(count: Int = 1) -> String { return self.substringToIndex(advance(self.endIndex, -count)) } } "hello".chopPrefix() // "ello" "hello".chopPrefix(3) // "lo" "hello".chopSuffix() // "hell" "hello".chopSuffix(3) // "he"
как
dropFirst
иdropLast
перед ними эти функции будут аварийно завершены, если в строке недостаточно букв. Бремя лежит на вызывающем абоненте, чтобы использовать их должным образом. Это обоснованное проектное решение. Можно было бы написать их, чтобы вернуть необязательный, который затем должен был бы быть развернут абонент.
на Swift 1.2, вам нужно позвонить
chopPrefix
такой:"hello".chopPrefix(count: 3) // "lo"
или вы можете добавить подчеркивание
_
к определениям функций для подавления имени параметра:extension String { func chopPrefix(_ count: Int = 1) -> String { return self.substringFromIndex(advance(self.startIndex, count)) } func chopSuffix(_ count: Int = 1) -> String { return self.substringToIndex(advance(self.endIndex, -count)) } }
Swift 2.2
'advance' недоступен: вызовите метод 'advancedBy (n)' в индексе
func chopPrefix(count: Int = 1) -> String { return self.substringFromIndex(self.startIndex.advancedBy(count)) } func chopSuffix(count: Int = 1) -> String { return self.substringFromIndex(self.endIndex.advancedBy(count)) }
Swift 3.0
func chopPrefix(_ count: Int = 1) -> String { return self.substring(from: self.characters.index(self.startIndex, offsetBy: count)) } func chopSuffix(_ count: Int = 1) -> String { return self.substring(to: self.characters.index(self.endIndex, offsetBy: -count)) }
Swift 3.2
представление содержимого строки в виде набора символов.
@available(swift, deprecated: 3.2, message: "Please use String or Substring directly") public var characters: String.CharacterView
func chopPrefix(_ count: Int = 1) -> String { if count >= 0 && count <= self.count { return self.substring(from: String.Index(encodedOffset: count)) } return "" } func chopSuffix(_ count: Int = 1) -> String { if count >= 0 && count <= self.count { return self.substring(to: String.Index(encodedOffset: self.count - count)) } return "" }
Swift 4
extension String { func chopPrefix(_ count: Int = 1) -> String { if count >= 0 && count <= self.count { let indexStartOfText = self.index(self.startIndex, offsetBy: count) return String(self[indexStartOfText...]) } return "" } func chopSuffix(_ count: Int = 1) -> String { if count >= 0 && count <= self.count { let indexEndOfText = self.index(self.endIndex, offsetBy: -count) return String(self[..<indexEndOfText]) } return "" } }
в Swift 2, сделайте следующее:
let cleanedString = String(theString.characters.dropFirst())
Я рекомендую https://www.mikeash.com/pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html чтобы получить представление о быстрых строках.
Как насчет этого?
s.removeAtIndex(s.startIndex)
Это, конечно, предполагает, что ваша строка изменчива. Она возвращает символ, который был удален, но изменяет исходную строку.
предыдущие ответы довольно хороши, но на сегодняшний день, я думаю, что это может быть самый краткий способ удалить первый символ из строки в Swift 4:
var line: String = "This is a string..." var char: Character? = nil char = line.removeFirst() print("char = \(char)") // char = T print("line = \(line)") // line = his is a string ...
зависит от того, что вы хотите, чтобы конечный результат был (мутация против немутации).
начиная с Swift 4.1:
мутирует:
var str = "hello" str.removeFirst() // changes str
Nonmutating:
let str = "hello" let strSlice = str.dropFirst() // makes a slice without the first letter let str2 = String(strSlice)
Примечания:
- я поставил дополнительный шаг в
nonmutating
пример для ясности. Субъективно, объединение последних двух шагов было бы более кратким.- название
dropFirst
мне кажется немного странным потому что если я понимаю Swift API Design Guidelines правильно,dropFirst
действительно должно быть что-то вродеdropingFirst
потому что это nonmutating. Просто мысль :).
Я не знаю ничего более емким из коробки, но вы можете легко реализовать префикс
++
, например,public prefix func ++ <I: ForwardIndexType>(index: I) -> I { return advance(index, 1) }
после чего вы можете использовать его в свое удовольствие очень лаконично:
str.substringFromIndex(++str.startIndex)
в Swift 2 Используйте это расширение строки:
extension String { func substringFromIndex(index: Int) -> String { if (index < 0 || index > self.characters.count) { print("index \(index) out of bounds") return "" } return self.substringFromIndex(self.startIndex.advancedBy(index)) } } display.text = display.text!.substringFromIndex(1)
"en_US, fr_CA, es_US".chopSuffix(5).chopPrefix(5) // ",fr_CA,"
extension String { func chopPrefix(count: Int = 1) -> String { return self.substringFromIndex(self.startIndex.advancedBy(count)) } func chopSuffix(count: Int = 1) -> String { return self.substringToIndex(self.endIndex.advancedBy(-count)) } }
Swift3
extension String { func chopPrefix(_ count: Int = 1) -> String { return substring(from: characters.index(startIndex, offsetBy: count)) } func chopSuffix(_ count: Int = 1) -> String { return substring(to: characters.index(endIndex, offsetBy: -count)) } } class StringChopTests: XCTestCase { func testPrefix() { XCTAssertEqual("original".chopPrefix(0), "original") XCTAssertEqual("Xfile".chopPrefix(), "file") XCTAssertEqual("filename.jpg".chopPrefix(4), "name.jpg") } func testSuffix() { XCTAssertEqual("original".chopSuffix(0), "original") XCTAssertEqual("fileX".chopSuffix(), "file") XCTAssertEqual("filename.jpg".chopSuffix(4), "filename") } }