Каков самый краткий способ удалить первый символ из строки в Swift?


Я хочу удалить первый символ из строки. До сих пор самая краткая вещь, которую я придумал, это:

display.text = display.text!.substringFromIndex(advance(display.text!.startIndex, 1))

Я знаю, что мы не можем индекса в строку с Int из-за Unicode, но это решение кажется ужасно многословным. Есть ли другой способ, который я упускаю из виду?

13 78

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")
    }
}

удалить первый символ из строки

let choppedString = String(txtField.text!.characters.dropFirst())

здесь Swift4 аварийное сохранение версии