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

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

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

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

Ответ 1

Если вы используете Swift 3, вы можете игнорировать второй раздел этого ответа. Хорошая новость заключается в том, что теперь это действительно кратким! Просто используя String new remove (at:) method.

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 и затем возвращаете результат в String. 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]

Ответ 2

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


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 перед ними, эти функции будут разбиваться, если в String недостаточно букв. Бремя зависит от того, используете ли вы его. Это действительное дизайнерское решение. Можно было бы написать их, чтобы вернуть опцию, которая затем должна быть развернута вызывающим абонентом.


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

Ответ 4

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 4

Вид содержимого строки в виде набора символов.

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

Ответ 5

Как насчет этого?

s.removeAtIndex(s.startIndex)

Это, конечно, предполагает, что ваша строка изменчива. Он возвращает символ, который был удален, но изменяет исходную строку.

Ответ 6

Я не знаю ничего более сжатого из коробки, но вы можете легко реализовать префикс ++, например,

public prefix func ++ <I: ForwardIndexType>(index: I) -> I {
    return advance(index, 1)
}

После этого вы можете использовать его в своем сердце очень кратко:

str.substringFromIndex(++str.startIndex)

Ответ 7

В 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)

Ответ 8

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

Ниже приведена версия Swift4 для аварийного восстановления расширения chopPrefix, оставив chopSuffix в сообществе...

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
        return count>self.count ? self : String(self[index(self.startIndex, offsetBy: count)...])
    }
 }