web-dev-qa-db-fra.com

Quel est le moyen le plus succinct pour supprimer le premier caractère d'une chaîne dans Swift?

Je veux supprimer le premier caractère d'une chaîne. Jusqu'ici, la chose la plus succincte que j'ai trouvée est:

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

Je sais que nous ne pouvons pas indexer dans une chaîne avec un Int à cause de Unicode, mais cette solution semble terriblement détaillée. Y a-t-il un autre moyen que je néglige?

88
SSteve

Si vous utilisez Swift 3 , vous pouvez ignorer la deuxième section de cette réponse. La bonne nouvelle est que ceci est de nouveau succinct! En utilisant simplement la nouvelle méthode remove (at :) de String.

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

myString // "Ello, World"

J'aime la fonction globale dropFirst() pour cela.

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

C'est court, clair et fonctionne pour tout ce qui est conforme au protocole Sliceable.

Si vous utilisez Swift 2 , cette réponse a changé. Vous pouvez toujours utiliser dropFirst, mais pas sans supprimer le premier caractère de votre propriété strings characters et reconvertir ensuite le résultat en chaîne. dropFirst est également devenu une méthode, pas une fonction.

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

Une autre alternative consiste à utiliser la fonction suffixe pour épisser le UTF16View de la chaîne. Bien sûr, cela doit également être reconverti en chaîne.

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

Tout cela pour dire que la solution que j'ai fournie à l'origine s'est avérée ne pas être la manière la plus succincte de le faire dans les nouvelles versions de Swift. Je recommande de recourir à la solution @chris avec removeAtIndex() si vous recherchez une solution courte et intuitive.

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

original // Ello

Et comme l'a souligné @vacawama dans les commentaires ci-dessous, une autre option qui ne modifie pas la chaîne d'origine consiste à utiliser substringFromIndex.

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

Ou si vous cherchez à supprimer un caractère du début et de la fin de la chaîne, vous pouvez utiliser substringWithRange. Veillez simplement à vous prémunir contre la situation lorsque 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 dernière ligne peut également être écrite en utilisant la notation en indice.

let substring = original[newStartIndex..<newEndIndex]
174
Mick MacCallum

Mise à jour pour Swift 4

Dans Swift 4, String est à nouveau conforme à Collection. Il est donc possible d'utiliser dropFirst et dropLast pour couper les débuts et les fins des chaînes. Le résultat est de type Substring, vous devez donc le transmettre au constructeur String pour récupérer une String:

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

dropFirst() et dropLast() utilisent également une Int pour spécifier le nombre de caractères à supprimer:

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

Si vous spécifiez plus de caractères à supprimer que dans la chaîne, le résultat sera la chaîne vide ("").

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

Mise à jour pour Swift 3

Si vous souhaitez simplement supprimer le premier caractère et modifier la chaîne d'origine, reportez-vous à la réponse de @ MickMacCallum. Si vous souhaitez créer une nouvelle chaîne dans le processus, utilisez substring(from:). Avec une extension à String, vous pouvez masquer la laideur de substring(from:) et substring(to:) afin de créer des ajouts utiles pour ajuster le début et la fin d'une 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"

Comme dropFirst et dropLast avant eux, ces fonctions se bloqueront si le nombre de lettres disponibles dans la chaîne est insuffisant. Il incombe à l'appelant de les utiliser correctement. Ceci est une décision de conception valide. On pourrait leur écrire pour renvoyer un optionnel qui devra alors être déballé par l'appelant.


Swift 2.x

Hélas, dans Swift 2 , dropFirst et dropLast (la meilleure solution précédente) ne sont plus aussi pratiques qu’avant. Avec une extension à String, vous pouvez masquer la laideur de substringFromIndex et 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"

Comme dropFirst et dropLast avant eux, ces fonctions se bloqueront si le nombre de lettres disponibles dans la chaîne est insuffisant. Il incombe à l'appelant de les utiliser correctement. Ceci est une décision de conception valide. On pourrait leur écrire pour renvoyer un optionnel qui devra alors être déballé par l'appelant.


Dans Swift 1.2 , vous devrez appeler chopPrefix comme ceci:

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

ou vous pouvez ajouter un trait de soulignement _ aux définitions de fonction pour supprimer le nom du paramètre:

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

Swift 2.2

'advance' n'est pas disponible: appelez la méthode 'advancedBy (n)' sur l'index

    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

Une vue du contenu de la chaîne en tant que collection de caractères.

@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
Jaleel Nazir

Dans Swift 2, procédez comme suit:

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

Je recommande https://www.mikeash.com/pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html pour bien comprendre Swins .

12
jrc

Et ça?

s.removeAtIndex(s.startIndex)

Bien entendu, cela suppose que votre chaîne est mutable. Il retourne le caractère qui a été supprimé, mais modifie la chaîne d'origine.

6
chris

Cela dépend de ce que vous voulez que le résultat final soit (mutant ou non mutant).

À partir de Swift 4.1:

En mutation:

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

Non mutable:

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

Remarques:

  • Pour plus de clarté, j’ai mis une étape supplémentaire dans l’exemple nonmutating. Subjectivement, la combinaison des deux dernières étapes serait plus succincte. 
  • Nommer dropFirst me semble un peu étrange, car si je comprends les Directives de conception de l'API Swift correctement, dropFirst devrait en réalité ressembler à dropingFirst car elle ne modifie pas. Juste une pensée :). 
5
jason z

Les réponses précédentes sont plutôt bonnes, mais à partir d’aujourd’hui, je pense que c’est peut-être le moyen le plus succinct d’enlever le premier caractère d’une chaîne dans 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 ...
2
ByteSlinger

Je ne connais rien de plus succinct, mais vous pouvez facilement implémenter le préfixe ++, par exemple,

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

Après quoi, vous pouvez l’utiliser de manière très succincte:

str.substringFromIndex(++str.startIndex)
1
Gregory Higley

"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
Andy

Dans Swift 2, utilisez cette extension String:

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
ChikabuZ

Swift3

extension String {
    func chopPrefix(_ count: UInt = 1) -> String {
        return substring(from: characters.index(startIndex, offsetBy: Int(count)))
    }

    func chopSuffix(_ count: UInt = 1) -> String {
        return substring(to: characters.index(endIndex, offsetBy: -Int(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")
    }
}
0
neoneye

Voici une version Swift4 crash de la version chopPrefix, en laissant chopSuffix à la communauté ...

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

Pour supprimer le premier caractère de la chaîne

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