Swift Substring to String

ParTobias Stephan

Swift Substring to String

Ces opérations sur les cordes en Swift peuvent vous rendre fou même si vous êtes habitué à un simple à partir du C#. C’est pourquoi je me suis penché sur la question et j’ai rassemblé un peu de ça. Ceci a été testé avec le Swift 5.1

  • startIndex est l’indice du premier caractères
  • endIndex est l’index après le dernier caractère
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let str = "Hello, playground"
        print(str[str.startIndex]) // H
        //print(str[str.endIndex])   // error: after last character

        let rangeStartToEnd = str.startIndex..<str.endIndex
        print("Range: " + str[rangeStartToEnd])  // "Hello, playground"

        let rangeWithoutGround = str.startIndex..<str.index(of: "ground")!
        print("Range: " + str[rangeWithoutGround])  // "Hello, playground"
    }

before fait référence à l’index du caractère qui précède directement l’index spécifié.

// character
let index = str.index(before: str.endIndex)
str[index] 

// range
let range = str.startIndex..<str.index(before: str.endIndex)
str[range]

La valeur OffsetBy peut être positive ou négative et part de l’indice spécifié. Bien qu’il soit de type String.IndexDistance, vous pouvez passer une valeur Int.

// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index]

// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
str[range]

Le limitedBy est utile pour s’assurer que le décalage n’entraîne pas le dépassement des limites de l’indice. C’est un indice limite. Comme il est possible que le décalage dépasse la limite, cette méthode renvoie une option. Il retourne zéro si l’indice est en dehors des limites.

if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
    str[index]
}

Si le “offset” avait été 77 au lieu de 7, l’énoncé if aurait été sauté.

Warum denn nun der ganze Umstand?

Il serait beaucoup plus facile d’utiliser un index Int pour les cordes. La raison pour laquelle vous devez créer un nouveau String.index pour chaque chaîne est que les caractères dans Swift ne sont pas tous de la même longueur sous le capot. Un seul caractère Swift peut être constitué d’un, deux ou même plusieurs points de code Unicode. Par conséquent, chaque chaîne unique doit calculer les indices de ses caractères.

Il est possible de cacher cette complexité derrière une extension d’index Int, mais j’hésite à le faire. Il est bon de se rappeler ce qui se passe réellement.

Une extension utile

L’Extenson suivant doit être ajouté sous votre classe dans le code. Cette extension vous offre la possibilité de déterminer l’index d’une chaîne entière dans une chaîne de caractères. Dans mon exemple “terre”.

Les opérations sur les chaînes de caractères sont donc traitées par le biais d’indices et de plages. L’indice n’est donc pas une simple variable integer.

extension StringProtocol {
    func index<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? {
        range(of: string, options: options)?.lowerBound
    }
    func endIndex<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? {
        range(of: string, options: options)?.upperBound
    }
    func indices<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Index] {
        var indices: [Index] = []
        var startIndex = self.startIndex
        while startIndex < endIndex,
            let range = self[startIndex...]
                .range(of: string, options: options) {
                indices.append(range.lowerBound)
                startIndex = range.lowerBound < range.upperBound ? range.upperBound :
                    index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
        }
        return indices
    }
    func ranges<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Range<Index>] {
        var result: [Range<Index>] = []
        var startIndex = self.startIndex
        while startIndex < endIndex,
            let range = self[startIndex...]
                .range(of: string, options: options) {
                result.append(range)
                startIndex = range.lowerBound < range.upperBound ? range.upperBound :
                    index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
        }
        return result
    }
}

À propos de l’auteur

Tobias Stephan administrator

Laisser un commentaire