Comment fonctionne la sous-chaîne String dans Swift

354

J'ai mis à jour certains de mes anciens codes et réponses avec Swift 3, mais quand je suis arrivé à Swift Strings et Indexing with substrings, les choses sont devenues confuses.

Plus précisément, j'essayais ce qui suit:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

où la deuxième ligne me donnait l'erreur suivante

La valeur de type 'String' n'a pas de membre 'substringWithRange'

Je vois que Stringcela a maintenant les méthodes suivantes:

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

Cela m'a vraiment dérouté au début, alors j'ai commencé à jouer sur l' index et la plage . Il s'agit d'une question et réponse de suivi pour la sous-chaîne. J'ajoute une réponse ci-dessous pour montrer comment ils sont utilisés.

Suragch
la source
2
Pour ceux qui veulent obtenir la sous-chaîne de la chaîne stackoverflow.com/q/32305891/468724
Inder Kumar Rathore
ou chaîne d' index
Leo Dabus

Réponses:

832

entrez la description de l'image ici

Tous les exemples suivants utilisent

var str = "Hello, playground"

Swift 4

Les chaînes ont subi une refonte assez importante dans Swift 4. Lorsque vous obtenez une sous-chaîne à partir d'une chaîne maintenant, vous récupérez un Substringtype plutôt qu'un String. Pourquoi est-ce? Les chaînes sont des types de valeur dans Swift. Cela signifie que si vous utilisez une chaîne pour en créer une nouvelle, elle doit être copiée. C'est bon pour la stabilité (personne d'autre ne va le changer à votre insu) mais mauvais pour l'efficacité.

Une sous-chaîne, d'autre part, est une référence à la chaîne d'origine dont elle est issue. Voici une image de la documentation illustrant cela.

Aucune copie n'est nécessaire, il est donc beaucoup plus efficace à utiliser. Cependant, imaginez que vous ayez une sous-chaîne de dix caractères à partir d'une chaîne d'un million de caractères. Étant donné que la sous-chaîne fait référence à la chaîne, le système doit conserver la chaîne entière aussi longtemps que la sous-chaîne est présente. Ainsi, chaque fois que vous avez fini de manipuler votre sous-chaîne, convertissez-la en chaîne.

let myString = String(mySubstring)

Cela ne copiera que la sous-chaîne et la mémoire contenant l'ancienne chaîne peut être récupérée . Les sous-chaînes (en tant que type) sont censées être de courte durée.

Une autre grande amélioration dans Swift 4 est que les cordes sont des collections (encore). Cela signifie que tout ce que vous pouvez faire pour une collection, vous pouvez le faire pour une chaîne (utilisez des indices, parcourez les caractères, filtrez, etc.).

Les exemples suivants montrent comment obtenir une sous-chaîne dans Swift.

Obtention de sous-chaînes

Vous pouvez obtenir une chaîne d'une chaîne à l'aide ou plusieurs indices d'autres méthodes (par exemple prefix, suffix, split). Cependant, vous devez toujours utiliser String.Indexet non un Intindex pour la plage. (Voir mon autre réponse si vous avez besoin d'aide à ce sujet.)

Début d'une chaîne

Vous pouvez utiliser un indice (notez la plage unilatérale de Swift 4):

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello

ou prefix:

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello

ou encore plus simple:

let mySubstring = str.prefix(5) // Hello

Fin d'une chaîne

Utilisation d'indices:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground

ou suffix:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground

ou encore plus simple:

let mySubstring = str.suffix(10) // playground

Notez que lors de l'utilisation du suffix(from: index)je devais recompter de la fin en utilisant -10. Cela n'est pas nécessaire lors de l'utilisation suffix(x), qui ne prend que les derniers xcaractères d'une chaîne.

Plage dans une chaîne

Encore une fois, nous utilisons simplement des indices ici.

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

let mySubstring = str[range]  // play

Conversion SubstringenString

N'oubliez pas, lorsque vous êtes prêt à enregistrer votre sous-chaîne, vous devez la convertir en un Stringafin que la mémoire de l'ancienne chaîne puisse être nettoyée.

let myString = String(mySubstring)

Vous utilisez une Intextension d'index?

J'hésite à utiliser une Intextension d'index basée après avoir lu l'article Strings dans Swift 3 par Airspeed Velocity et Ole Begemann. Bien que dans Swift 4, les chaînes soient des collections, l'équipe Swift n'a délibérément pas utilisé d' Intindex. C'est encore String.Index. Cela a à voir avec les caractères Swift étant composés de nombres variables de points de code Unicode. L'index réel doit être calculé de manière unique pour chaque chaîne.

Je dois dire que j'espère que l'équipe Swift trouvera un moyen d'abstraire String.Indexà l'avenir. Mais jusqu'à eux, je choisis d'utiliser leur API. Cela m'aide à me rappeler que les manipulations de chaînes ne sont pas seulement de simples Intrecherches d'index.

Suragch
la source
9
Thx pour la description. Uprates bien mérités. Apple a trop compliqué cela. La sous-chaîne doit être aussi simple que string.substring [de ... à].
Teddy
Vraiment une bonne explication. sauf une petite chose garbage collected;-) J'espère que les gens d'ici savent qu'il n'y a pas de collecte des ordures dans Swift.
Christian Anchor Dampf
@ChristianAnchorDampf, Merci d'avoir pris le temps de commenter. J'ai sorti la collecte des ordures. Comment est le nouveau libellé?
Suragch
Quelle réponse étonnante monsieur !!
davidev
194

Je suis vraiment frustré par le modèle d'accès aux chaînes de Swift: tout doit être un Index. Tout ce que je veux, c'est accéder au i-ème caractère de la chaîne en utilisant Int, pas l'index maladroit et en avançant (ce qui arrive à changer avec chaque version majeure). J'ai donc fait une extension à String:

extension String {
    func index(from: Int) -> Index {
        return self.index(startIndex, offsetBy: from)
    }

    func substring(from: Int) -> String {
        let fromIndex = index(from: from)
        return String(self[fromIndex...])
    }

    func substring(to: Int) -> String {
        let toIndex = index(from: to)
        return String(self[..<toIndex])
    }

    func substring(with r: Range<Int>) -> String {
        let startIndex = index(from: r.lowerBound)
        let endIndex = index(from: r.upperBound)
        return String(self[startIndex..<endIndex])
    }
}

let str = "Hello, playground"
print(str.substring(from: 7))         // playground
print(str.substring(to: 5))           // Hello
print(str.substring(with: 7..<11))    // play
Code différent
la source
5
Les index sont très utiles car un caractère peut avoir plusieurs octets. Essayezlet str = "🇨🇭🇩🇪🇺🇸Hello" print(str.substring(to: 2))
vadian
112
Oui, je comprends qu'un caractère (c'est -à- dire un cluster de graphèmes étendu ) peut prendre plusieurs octets. Ma frustration est la raison pour laquelle nous devons utiliser la méthode avancée d'indexation verbeuse pour accéder aux caractères d'une chaîne. Pourquoi l'équipe de Swift ne peut-elle pas simplement ajouter des surcharges à la bibliothèque principale pour l'abstraire. Si je tape str[5], je veux accéder au caractère à l'index 5, quel que soit ce caractère ou combien d'octets il faut. Swift n'est-il pas tout au sujet de la productivité du développeur?
Code différent du
6
@RenniePet Je crois qu'Apple reconnaît le problème et les changements arrivent. Selon la page Swift Evolution sur GitHub: "Swift 4 cherche à rendre les chaînes plus puissantes et plus faciles à utiliser, tout en conservant l'exactitude Unicode par défaut". C'est vague mais gardons nos espoirs
Code différent
3
@CodeDifferent pourquoi apple n'a pas ajouté l'accès aux caractères en indice? Pour que les gens comprennent que c'est une mauvaise chose à faire. Fondamentalement, si vous le feriez pour i dans 0..string.count en utilisant des indices qui seraient en double boucle, car sous le capot, l'index doit parcourir chaque octet de chaîne pour savoir quel est le caractère suivant. Si vous effectuez une boucle à l'aide de l'index, vous ne parcourez la chaîne qu'une seule fois. Btw, je déteste ça moi-même, mais c'est le raisonnement derrière l'indice qui n'est pas disponible sur la chaîne en swift.
Raimundas Sakalauskas
4
@RaimundasSakalauskas cet argument ne passe pas à côté de moi. C # a à la fois l'exactitude Unicode et la souscription entière, ce qui est vraiment pratique. Dans Swift 1, Apple voulait que les développeurs utilisent countElement(str)pour trouver la longueur. Dans Swift 3, Apple a rendu la chaîne non conforme Sequenceet a forcé tout le monde à l'utiliser à la str.charactersplace. Ces gars-là n'ont pas peur de faire des changements. Leur entêtement sur l'indice entier est vraiment difficile à comprendre
Code Différent
103

Extension Swift 5:

extension String {
    subscript(_ range: CountableRange<Int>) -> String {
        let start = index(startIndex, offsetBy: max(0, range.lowerBound))
        let end = index(start, offsetBy: min(self.count - range.lowerBound, 
                                             range.upperBound - range.lowerBound))
        return String(self[start..<end])
    }

    subscript(_ range: CountablePartialRangeFrom<Int>) -> String {
        let start = index(startIndex, offsetBy: max(0, range.lowerBound))
         return String(self[start...])
    }
}

Usage:

let s = "hello"
s[0..<3] // "hel"
s[3...]  // "lo"

Ou unicode:

let s = "😎🤣😋"
s[0..<1] // "😎"
Lou Zell
la source
2
Tant mieux, merci d'avoir posté cette extension! Je pense qu'en provenance de Python, Swift est beaucoup plus difficile que nécessaire pour s'y habituer. Il semble que pour les gens qui vont dans l'autre sens de l'objectif C à Swift, la confirmation soit plus positive.
user3064009
1
@Leon Je viens de le retirer. Avant la version 4.1, countn'était disponible que surself.characters
Lou Zell
1
Y a-t-il des problèmes à surveiller avec cette extension particulière? Pourquoi Apple n'a-t-il pas fait quelque chose comme ça?
Andz
1
@Andz c'est très inefficace. Il commence au début de la chaîne - deux fois - et doit analyser chaque caractère à partir de là pour "plage" - deux fois.
kareman
3
Vous devrez également ajouter une extension qui prend unCountableClosedRange<Int> si vous souhaitez écrire par exemple s[0...2].
Chris Frederick
24

Swift 4 et 5:

extension String {
  subscript(_ i: Int) -> String {
    let idx1 = index(startIndex, offsetBy: i)
    let idx2 = index(idx1, offsetBy: 1)
    return String(self[idx1..<idx2])
  }

  subscript (r: Range<Int>) -> String {
    let start = index(startIndex, offsetBy: r.lowerBound)
    let end = index(startIndex, offsetBy: r.upperBound)
    return String(self[start ..< end])
  }

  subscript (r: CountableClosedRange<Int>) -> String {
    let startIndex =  self.index(self.startIndex, offsetBy: r.lowerBound)
    let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound)
    return String(self[startIndex...endIndex])
  }
}

Comment l'utiliser:

"abcde" [0] -> "a"

"abcde" [0 ... 2] -> "abc"

"abcde" [2 .. <4] -> "cd"

Souf ROCHDI
la source
20

Swift 4

Dans swift 4 Stringest conforme à Collection. Au lieu de substring, nous devons maintenant utiliser un subscript.Donc , si vous voulez couper uniquement le mot "play"de "Hello, playground", vous pouvez le faire comme ceci:

var str = "Hello, playground"
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let result = str[start..<end] // The result is of type Substring

Il est intéressant de savoir que cela vous donnera un Substringau lieu d'un String. C'est rapide et efficace car il Substringpartage son stockage avec la chaîne d'origine. Cependant, le partage de la mémoire de cette manière peut également facilement entraîner des fuites de mémoire.

C'est pourquoi vous devez copier le résultat dans une nouvelle chaîne, une fois que vous souhaitez nettoyer la chaîne d'origine. Vous pouvez le faire en utilisant le constructeur normal:

let newString = String(result)

Vous pouvez trouver plus d'informations sur la nouvelle Substringclasse dans la [documentation Apple]. 1

Donc, si vous obtenez par exemple un Rangerésultat d'un NSRegularExpression, vous pouvez utiliser l'extension suivante:

extension String {

    subscript(_ range: NSRange) -> String {
        let start = self.index(self.startIndex, offsetBy: range.lowerBound)
        let end = self.index(self.startIndex, offsetBy: range.upperBound)
        let subString = self[start..<end]
        return String(subString)
    }

}
gebirgsbärbel
la source
Votre code se bloquera si range.upperBound est> longueur de chaîne. En outre, un exemple d'utilisation aurait également été utile, car je ne connaissais pas les indices dans Swift. Vous pouvez inclure quelque chose comme datePartOnly = "2018-01-04-08: 00" [NSMakeRange (0, 10)]. A part ça, très belle réponse, +1 :).
dcp
de nos jours c'est cette chose bizarre: text[Range( nsRange , in: text)!]
Fattie
10

Voici une fonction qui renvoie la sous-chaîne d'une sous-chaîne donnée lorsque des indices de début et de fin sont fournis. Pour une référence complète, vous pouvez visiter les liens ci-dessous.

func substring(string: String, fromIndex: Int, toIndex: Int) -> String? {
    if fromIndex < toIndex && toIndex < string.count /*use string.characters.count for swift3*/{
        let startIndex = string.index(string.startIndex, offsetBy: fromIndex)
        let endIndex = string.index(string.startIndex, offsetBy: toIndex)
        return String(string[startIndex..<endIndex])
    }else{
        return nil
    }
}

Voici un lien vers le blog que j'ai créé pour traiter de la manipulation des chaînes dans swift. Manipulation des chaînes dans swift (couvre également swift 4)

Ou vous pouvez voir ce résumé sur github

Nikesh Jha
la source
9

J'ai eu la même réaction initiale. Moi aussi, j'étais frustré de voir comment la syntaxe et les objets changent si radicalement dans chaque version majeure.

Cependant, j'ai réalisé par expérience à quel point je finis toujours par subir les conséquences d'essayer de lutter contre le «changement», comme traiter avec des caractères multi-octets, ce qui est inévitable si vous regardez un public mondial.

J'ai donc décidé de reconnaître et de respecter les efforts déployés par les ingénieurs d'Apple et de faire ma part en comprenant leur état d'esprit lorsqu'ils ont proposé cette approche "horrible".

Au lieu de créer des extensions qui ne sont qu'une solution de contournement pour vous faciliter la vie (je ne dis pas qu'elles sont erronées ou coûteuses), pourquoi ne pas comprendre comment les chaînes sont maintenant conçues pour fonctionner.

Par exemple, j'avais ce code qui fonctionnait sur Swift 2.2:

let rString = cString.substringToIndex(2)
let gString = (cString.substringFromIndex(2) as NSString).substringToIndex(2)
let bString = (cString.substringFromIndex(4) as NSString).substringToIndex(2)

et après avoir renoncé à essayer de faire fonctionner la même approche, par exemple en utilisant des sous-chaînes, j'ai finalement compris le concept de traiter les chaînes comme une collection bidirectionnelle pour laquelle je me suis retrouvé avec cette version du même code:

let rString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let gString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let bString = String(cString.characters.prefix(2))

J'espère que cela contribue ...

Rio Bautista
la source
1
Eh bien, traiter un problème complexe ne signifie pas que la solution pourrait être élégante. Encore une fois, je comprends également le problème, mais toute la classe String et son traitement sont tout simplement horribles.
inexcit
5

Même frustration, ça ne devrait pas être si difficile ...

J'ai compilé cet exemple d'obtention de positions pour des sous-chaînes à partir d'un texte plus grand:

//
// Play with finding substrings returning an array of the non-unique words and positions in text
//
//

import UIKit

let Bigstring = "Why is it so hard to find substrings in Swift3"
let searchStrs : Array<String>? = ["Why", "substrings", "Swift3"]

FindSubString(inputStr: Bigstring, subStrings: searchStrs)


func FindSubString(inputStr : String, subStrings: Array<String>?) ->    Array<(String, Int, Int)> {
    var resultArray : Array<(String, Int, Int)> = []
    for i: Int in 0...(subStrings?.count)!-1 {
        if inputStr.contains((subStrings?[i])!) {
            let range: Range<String.Index> = inputStr.range(of: subStrings![i])!
            let lPos = inputStr.distance(from: inputStr.startIndex, to: range.lowerBound)
            let uPos = inputStr.distance(from: inputStr.startIndex, to: range.upperBound)
            let element = ((subStrings?[i])! as String, lPos, uPos)
            resultArray.append(element)
        }
    }
    for words in resultArray {
        print(words)
    }
    return resultArray
}

renvoie ("Pourquoi", 0, 3) ("sous-chaînes", 26, 36) ("Swift3", 40, 46)

Grand Danois
la source
3
C'est du code, mais n'explique pas vraiment comment l'indexation des chaînes et les sous-chaînes fonctionnent dans swift3.
Robert
5

Je suis nouveau dans Swift 3, mais en regardant la Stringsyntaxe (index) pour l'analogie, je pense que l'index est comme un "pointeur" contraint à la chaîne et Int peut aider en tant qu'objet indépendant. En utilisant la syntaxe base + offset, nous pouvons alors obtenir le i-ème caractère de la chaîne avec le code ci-dessous:

let s = "abcdefghi"
let i = 2
print (s[s.index(s.startIndex, offsetBy:i)])
// print c

Pour une plage de caractères (index) de chaîne en utilisant la syntaxe de chaîne (plage), nous pouvons obtenir des caractères i-ème à f-ème avec le code ci-dessous:

let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg

Pour une sous-chaîne (plage) à partir d'une chaîne utilisant String.substring (plage), nous pouvons obtenir la sous-chaîne en utilisant le code ci-dessous:

print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg

Remarques:

  1. Les i-ème et f-ème commencent par 0.

  2. Pour f-ème, j'utilise offsetBY: f + 1, car la plage d'utilisation de l'abonnement .. <(opérateur semi-ouvert), n'inclut pas la f-ème position.

  3. Bien sûr, doit inclure des erreurs de validation comme un index non valide.

Nelson Mizutani
la source
5

Swift 4+

extension String {
    func take(_ n: Int) -> String {
        guard n >= 0 else {
            fatalError("n should never negative")
        }
        let index = self.index(self.startIndex, offsetBy: min(n, self.count))
        return String(self[..<index])
    }
}

Renvoie une sous-séquence des n premiers caractères ou la chaîne entière si la chaîne est plus courte. (inspiré par: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html )

Exemple:

let text = "Hello, World!"
let substring = text.take(5) //Hello
Peter Kreinz
la source
4

Je pense assez mécaniquement. Voici les bases ...

Swift 4 Swift 5

  let t = "abracadabra"

  let start1 = t.index(t.startIndex, offsetBy:0)
  let   end1 = t.index(t.endIndex, offsetBy:-5)
  let start2 = t.index(t.endIndex, offsetBy:-5)
  let   end2 = t.index(t.endIndex, offsetBy:0)

  let t2 = t[start1 ..< end1]
  let t3 = t[start2 ..< end2]                

  //or a shorter form 

  let t4 = t[..<end1]
  let t5 = t[start2...]

  print("\(t2) \(t3) \(t)")
  print("\(t4) \(t5) \(t)")

  // result:
  // abraca dabra abracadabra

Le résultat est une sous-chaîne, ce qui signifie qu'elle fait partie de la chaîne d'origine. Pour obtenir une chaîne séparée complète, utilisez par exemple

    String(t3)
    String(t4)

Voici ce que j'utilise:

    let mid = t.index(t.endIndex, offsetBy:-5)
    let firstHalf = t[..<mid]
    let secondHalf = t[mid...]
t1ser
la source
3

Swift 4

extension String {
    subscript(_ i: Int) -> String {
        let idx1 = index(startIndex, offsetBy: i)
        let idx2 = index(idx1, offsetBy: 1)
        return String(self[idx1..<idx2])
    }
}

let s = "hello"

s[0]    // h
s[1]    // e
s[2]    // l
s[3]    // l
s[4]    // o
FlowUI. SimpleUITesting.com
la source
2

J'ai créé une extension simple pour cela (Swift 3)

extension String {
    func substring(location: Int, length: Int) -> String? {
        guard characters.count >= location + length else { return nil }
        let start = index(startIndex, offsetBy: location)
        let end = index(startIndex, offsetBy: location + length)
        return substring(with: start..<end)
    }
}
Lucas Algarra
la source
2

Voici une implémentation plus générique:

Cette technique utilise toujours indexpour respecter les normes de Swift et impliquer un personnage complet.

extension String
{
    func subString <R> (_ range: R) -> String? where R : RangeExpression, String.Index == R.Bound
    {
        return String(self[range])
    }

    func index(at: Int) -> Index
    {
        return self.index(self.startIndex, offsetBy: at)
    }
}

Pour sous-chaîne à partir du 3e caractère:

let item = "Fred looks funny"
item.subString(item.index(at: 2)...) // "ed looks funny"

J'ai utilisé du chameau subStringpour indiquer qu'il renvoie un Stringet non un Substring.

Leslie Godwin
la source
2

Sur la base de ce qui précède, je devais diviser une chaîne au niveau d'un caractère non imprimable en supprimant le caractère non imprimable. J'ai développé deux méthodes:

var str = "abc\u{1A}12345sdf"
let range1: Range<String.Index> = str.range(of: "\u{1A}")!
let index1: Int = str.distance(from: str.startIndex, to: range1.lowerBound)
let start = str.index(str.startIndex, offsetBy: index1)
let end = str.index(str.endIndex, offsetBy: -0)
let result = str[start..<end] // The result is of type Substring
let firstStr = str[str.startIndex..<range1.lowerBound]

que j'ai rassemblé en utilisant certaines des réponses ci-dessus.

Parce qu'une chaîne est une collection, j'ai ensuite fait ce qui suit:

var fString = String()
for (n,c) in str.enumerated(){

*if c == "\u{1A}" {
    print(fString);
    let lString = str.dropFirst(n + 1)
    print(lString)
    break
   }
 fString += String(c)
}*

Ce qui pour moi était plus intuitif. Laquelle est la meilleure? Je n'ai aucun moyen de dire qu'ils travaillent tous les deux avec Swift 5

Jeremy Andrews
la source
Merci pour votre réponse. Y a-t-il quelque chose de différent avec Strings dans Swift 5? Je n'ai pas encore eu le temps de jouer avec.
Suragch
Ils le disent mais je n'ai pas eu l'occasion de m'y intéresser.
Jeremy Andrews
1

Swift 4

"Sous-chaîne" ( https://developer.apple.com/documentation/swift/substring ):

let greeting = "Hi there! It's nice to meet you! 👋"
let endOfSentence = greeting.index(of: "!")!
let firstSentence = greeting[...endOfSentence]
// firstSentence == "Hi there!"

Exemple d'extension de chaîne:

private typealias HowDoYouLikeThatElonMusk = String
private extension HowDoYouLikeThatElonMusk {

    subscript(_ from: Character?, _ to: Character?, _ include: Bool) -> String? {
        if let _from: Character = from, let _to: Character = to {
            let dynamicSourceForEnd: String = (_from == _to ? String(self.reversed()) : self)
            guard let startOfSentence: String.Index = self.index(of: _from),
                let endOfSentence: String.Index = dynamicSourceForEnd.index(of: _to) else {
                return nil
            }

            let result: String = String(self[startOfSentence...endOfSentence])
            if include == false {
                guard result.count > 2 else {
                        return nil
                }
                return String(result[result.index(result.startIndex, offsetBy: 1)..<result.index(result.endIndex, offsetBy: -1)])
            }
            return result
        } else if let _from: Character = from {
            guard let startOfSentence: String.Index = self.index(of: _from) else {
                return nil
            }
            let result: String = String(self[startOfSentence...])
            if include == false {
                guard result.count > 1 else {
                    return nil
                }
                return String(result[result.index(result.startIndex, offsetBy: 1)...])
            }
            return result
        } else if let _to: Character = to {
            guard let endOfSentence: String.Index = self.index(of: _to) else {
                    return nil
            }
            let result: String = String(self[...endOfSentence])
            if include == false {
                guard result.count > 1 else {
                    return nil
                }
                return String(result[..<result.index(result.endIndex, offsetBy: -1)])
            }
            return result
        }
        return nil
    }
}

exemple d'utilisation de l'extension String:

let source =                                   ">>>01234..56789<<<"
// include = true
var from =          source["3", nil, true]  //       "34..56789<<<"
var to =            source[nil, "6", true]  // ">>>01234..56"
var fromTo =        source["3", "6", true]  //       "34..56"
let notFound =      source["a", nil, true]  // nil
// include = false
from =              source["3", nil, false] //        "4..56789<<<"
to =                source[nil, "6", false] // ">>>01234..5"
fromTo =            source["3", "6", false] //        "4..5"
let outOfBounds =   source[".", ".", false] // nil

let str = "Hello, playground"
let hello = str[nil, ",", false] // "Hello"
CAHbl463
la source
-1

Swift 5
let desiredIndex: Int = 7 let substring = str[String.Index(encodedOffset: desiredIndex)...]
Cette variable de sous-chaîne vous donnera le résultat.
Simplement ici, Int est converti en Index et vous pouvez ensuite diviser les chaînes. À moins que vous n'obteniez des erreurs.

Wimukthi Rajapaksha
la source
2
C'est faux. Un caractère peut consister en un ou plusieurs octets. Cela ne fonctionne qu'avec du texte ascii.
Leo Dabus