Pregunta ¿Cuál es la forma más sucinta de eliminar el primer carácter de una cadena en Swift?


Quiero eliminar el primer caracter de una cadena. Hasta ahora, lo más breve que he encontrado es:

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

Sé que no podemos indexar en una cadena con un Int debido a Unicode, pero esta solución parece terriblemente detallada. ¿Hay alguna otra manera que estoy pasando por alto?


74
2018-02-11 03:07


origen


Respuestas:


Si estás usando Swift 3, puedes ignorar la segunda sección de esta respuesta. ¡Buenas noticias es que ahora esto es realmente sucinto otra vez! Simplemente usando el nuevo método remove (at :) de String.

var myString = "Hello, World"
myString.remove(at: myString.startIndex)

myString // "ello, World"

Me gusta el mundo dropFirst() función para esto.

let original = "Hello" // Hello
let sliced = dropFirst(original) // ello

Es breve, claro, y funciona para todo lo que se ajuste al protocolo Sliceable.

Si estás usando Swift 2, esta respuesta ha cambiado. Todavía puede usar dropFirst, pero no sin dejar caer el primer carácter de sus cadenas characters propiedad y luego convertir el resultado a una Cadena. dropFirst también se ha convertido en un método, no en una función.

let original = "Hello" // Hello
let sliced = String(original.characters.dropFirst()) // ello

Otra alternativa es usar la función de sufijo para empalmar la cadena UTF16View. Por supuesto, esto tiene que ser convertido nuevamente a una Cadena después.

let original = "Hello" // Hello
let sliced = String(suffix(original.utf16, original.utf16.count - 1)) // ello

Todo esto quiere decir que la solución que proporcioné originalmente no resultó ser la forma más concisa de hacerlo en las versiones más nuevas de Swift. Recomiendo recurrir a la solución de @chris usando removeAtIndex() si estás buscando una solución corta e intuitiva.

var original = "Hello" // Hello
let removedChar = original.removeAtIndex(original.startIndex)

original // ello

Y como lo señala @vacawama en los comentarios a continuación, otra opción que no modifica la cadena original es usar substringFromIndex.

let original = "Hello" // Hello
let substring = original.substringFromIndex(advance(original.startIndex, 1)) // ello

O si está buscando dejar un personaje al principio y al final de la cadena, puede usar substringWithRange. Solo asegúrese de protegerse contra la condición cuando 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

La última línea también se puede escribir utilizando notación de subíndice.

let substring = original[newStartIndex..<newEndIndex]

156
2018-02-11 03:31



Actualización para Swift 4

En Swift 4, String De acuerdo a Collection nuevamente, entonces es posible usar dropFirst y dropLast para recortar los comienzos y los extremos de las cuerdas. El resultado es de tipo Substring, entonces debes pasar eso a la String constructor para volver a una String:

let str = "hello"
let result1 = String(str.dropFirst())    // "ello"
let result2 = String(str.dropLast())     // "hell"

dropFirst() y dropLast() también toma una Int para especificar la cantidad de caracteres a soltar:

let result3 = String(str.dropLast(3))    // "he"
let result4 = String(str.dropFirst(4))   // "o"

Si especifica más caracteres para colocar que los que están en la cadena, el resultado será la cadena vacía ("")

let result5 = String(str.dropFirst(10))  // ""

Actualización para Swift 3

Si solo desea eliminar el primer carácter y desea cambiar la cadena original en su lugar, vea la respuesta de @MickMacCallum. Si desea crear una nueva cadena en el proceso, use substring(from:). Con una extensión a String, puedes ocultar la fealdad de substring(from:) y substring(to:) para crear adiciones útiles para recortar el inicio y el final de un 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"

Me gusta dropFirst y dropLast antes de ellos, estas funciones se bloquearán si no hay suficientes letras disponibles en el String. La persona que llama tiene la responsabilidad de usarlos adecuadamente. Esta es una decisión de diseño válida. Uno podría escribirlos para devolver un opcional que luego tendría que ser desenvuelto por la persona que llama.


Swift 2.x

Por desgracia en Swift 2, dropFirst y dropLast (la mejor solución anterior) no es tan conveniente como lo eran antes. Con una extensión a String, puedes ocultar la fealdad de substringFromIndex y 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"

Me gusta dropFirst y dropLast antes de ellos, estas funciones se bloquearán si no hay suficientes letras disponibles en el String. La persona que llama tiene la responsabilidad de usarlos adecuadamente. Esta es una decisión de diseño válida. Uno podría escribirlos para devolver un opcional que luego tendría que ser desenvuelto por la persona que llama.


En Swift 1.2, deberás llamar chopPrefix Me gusta esto:

"hello".chopPrefix(count: 3)  // "lo"

o puedes agregar un guion bajo _ a las definiciones de función para suprimir el nombre del parámetro:

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

70
2018-06-14 13:34



Swift 2.2

'advance' no está disponible: llame al método 'advancedBy (n)' en el índice

    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

Una vista de los contenidos de la cadena como una colección de caracteres.

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

15
2018-06-14 10:20



En Swift 2, haz esto:

let cleanedString = String(theString.characters.dropFirst())

yo recomiendo https://www.mikeash.com/pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html para entender las cadenas de Swift.


12
2017-08-29 12:30



¿Qué hay de esto?

s.removeAtIndex(s.startIndex)

Por supuesto, esto supone que su cadena es mutable. Devuelve el carácter que se ha eliminado, pero altera la cadena original.


6
2018-02-11 03:15



No sé nada más sucinto de la caja, pero podría implementar fácilmente el prefijo ++, p.ej.,

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

Después de lo cual puedes usarlo al contenido de tu corazón de manera muy sucinta:

str.substringFromIndex(++str.startIndex)

1
2018-02-11 03:12



En Swift 2 usa esta extensión de cadena:

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)

1
2017-09-22 14:37



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

1
2018-06-30 04:15



Las respuestas anteriores son bastante buenas, pero a partir de hoy, creo que esta puede ser la manera más sucinta de eliminar el primer personaje de una cadena en 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 ...

1
2018-01-22 19:19



Depende de lo que quieras que sea el resultado final (mutación versus no mutación).

A partir de Swift 4.1:

Mutar:

var str = "hello"
str.removeFirst() // changes str 

No mudante:

let str = "hello"
let strSlice = str.dropFirst() // makes a slice without the first letter
let str2 = String(strSlice)

Notas:

  • Puse un paso extra en el nonmutating ejemplo de claridad. Subjetivamente, la combinación de los dos últimos pasos sería más sucinta.
  • El nombramiento de dropFirst me parece un poco extraño porque si comprendo el Pautas de diseño de la API Swift correctamente, dropFirst debería ser algo así como dropingFirst porque es inmutable. Solo un pensamiento :).

1
2018-05-03 11:05