Swift: Comment obtenir une sous-chaîne du début au dernier index du caractère

110

Je veux apprendre la meilleure / la plus simple façon de transformer une chaîne en une autre chaîne, mais avec seulement un sous-ensemble, en commençant par le début et en allant au dernier index d'un caractère.

Par exemple, convertissez «www.stackoverflow.com» en «www.stackoverflow». Quel extrait de code ferait cela, et étant le plus rapide? (J'espère que cela n'apportera pas de débat, mais je ne trouve pas de bonne leçon sur la façon de gérer les sous-chaînes dans Swift.

Jason Hocker
la source

Réponses:

202

Accès juste en arrière

Le meilleur moyen est d'utiliser substringToIndexcombiné à la endIndexpropriété et à la advancefonction globale.

var string1 = "www.stackoverflow.com"

var index1 = advance(string1.endIndex, -4)

var substring1 = string1.substringToIndex(index1)

A la recherche d'une corde partant de l'arrière

Utiliser rangeOfStringet régler optionssur.BackwardsSearch

var string2 = "www.stackoverflow.com"

var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex

var substring2 = string2.substringToIndex(index2!)

Pas d'extensions, Swift idiomatique pur

Swift 2.0

advancefait maintenant partie de Indexet est appelé advancedBy. Vous le faites comme:

var string1 = "www.stackoverflow.com"

var index1 = string1.endIndex.advancedBy(-4)

var substring1 = string1.substringToIndex(index1)

Swift 3.0

Vous ne pouvez pas appeler advancedBya Stringcar il contient des éléments de taille variable. Vous devez utiliser index(_, offsetBy:).

var string1 = "www.stackoverflow.com"

var index1 = string1.index(string1.endIndex, offsetBy: -4)

var substring1 = string1.substring(to: index1)

Beaucoup de choses ont été renommées. Les cas sont écrits en camelCase, startIndexest devenu lowerBound.

var string2 = "www.stackoverflow.com"

var index2 = string2.range(of: ".", options: .backwards)?.lowerBound

var substring2 = string2.substring(to: index2!)

De plus, je ne recommanderais pas le déballage forcé index2. Vous pouvez utiliser la liaison facultative ou map. Personnellement, je préfère utiliser map:

var substring3 = index2.map(string2.substring(to:))

Swift 4

La version Swift 3 est toujours valide mais vous pouvez désormais utiliser des indices avec des plages d'index:

let string1 = "www.stackoverflow.com"

let index1 = string1.index(string1.endIndex, offsetBy: -4)

let substring1 = string1[..<index1]

La deuxième approche reste inchangée:

let string2 = "www.stackoverflow.com"

let index2 = string2.range(of: ".", options: .backwards)?.lowerBound

let substring3 = index2.map(string2.substring(to:))
fpg1503
la source
1
Merci @ fpg1503. C'est le genre de réponse que je cherchais à trouver. Les autres réponses m'ont appris ou m'ont rappelé les fonctionnalités du langage, mais c'est ainsi que j'utiliserai pour résoudre mon problème.
Jason Hocker
1
Utiliser Swift 2.0, string1.endIndex.advancedBy(-4)ça marche pour moi au lieu deadvance
Alex Koshy
92
N'y a-t-il vraiment aucun moyen de faire cela simplement?
devios1
12
@devios tout est vrai. Je suis reconnaissant pour Swift par rapport à Objective-C, mais à mon humble avis, les préoccupations qui mènent à ce code incroyablement maladroit ne sont pas pertinentes pour 99% du code et des codeurs. Pire encore, nous finirons par écrire nous-mêmes de mauvaises extensions de commodité. Si les développeurs réguliers ne peuvent pas comprendre ces préoccupations de plus haut niveau, ils sont les MOINS capables d'écrire une API ad-hoc pour traiter les problèmes des piétons avec lesquels nous créons des logiciels. La tendance à se convertir NSStringest évidemment mauvaise, aussi, parce que finalement nous voulons tous nous éloigner des classes de la Fondation (héritage). Alors ... plus de déclamations!
Dan Rosenstark
2
Dans Swift 4, vous pouvez le faire string1[..<index1]. Pas besoin de string1.startIndex.
bauerMusic
26

Swift 3, XCode 8

func lastIndexOfCharacter(_ c: Character) -> Int? {
    return range(of: String(c), options: .backwards)?.lowerBound.encodedOffset
}

Depuis advancedBy(Int)est parti depuis que Swift 3 utilise Stringla méthode index(String.Index, Int). Découvrez cette Stringextension avec sous-chaîne et amis:

public extension String {

    //right is the first encountered string after left
    func between(_ left: String, _ right: String) -> String? {
        guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
        , leftRange.upperBound <= rightRange.lowerBound
            else { return nil }

        let sub = self.substring(from: leftRange.upperBound)
        let closestToLeftRange = sub.range(of: right)!
        return sub.substring(to: closestToLeftRange.lowerBound)
    }

    var length: Int {
        get {
            return self.characters.count
        }
    }

    func substring(to : Int) -> String {
        let toIndex = self.index(self.startIndex, offsetBy: to)
        return self.substring(to: toIndex)
    }

    func substring(from : Int) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: from)
        return self.substring(from: fromIndex)
    }

    func substring(_ r: Range<Int>) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        return self.substring(with: Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex)))
    }

    func character(_ at: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: at)]
    }

    func lastIndexOfCharacter(_ c: Character) -> Int? {
        guard let index = range(of: String(c), options: .backwards)?.lowerBound else
        { return nil }
        return distance(from: startIndex, to: index)
    }
}

Extension MISE À JOUR pour Swift 4

public extension String {

    //right is the first encountered string after left
    func between(_ left: String, _ right: String) -> String? {
        guard
            let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
            , leftRange.upperBound <= rightRange.lowerBound
            else { return nil }

        let sub = self[leftRange.upperBound...]
        let closestToLeftRange = sub.range(of: right)!            
        return String(sub[..<closestToLeftRange.lowerBound])
    }

    var length: Int {
        get {
            return self.count
        }
    }

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

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

    func substring(_ r: Range<Int>) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        let indexRange = Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))
        return String(self[indexRange])
    }

    func character(_ at: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: at)]
    }

    func lastIndexOfCharacter(_ c: Character) -> Int? {
        guard let index = range(of: String(c), options: .backwards)?.lowerBound else
        { return nil }
        return distance(from: startIndex, to: index)
    }
}

Usage:

let text = "www.stackoverflow.com"
let at = text.character(3) // .
let range = text.substring(0..<3) // www
let from = text.substring(from: 4) // stackoverflow.com
let to = text.substring(to: 16) // www.stackoverflow
let between = text.between(".", ".") // stackoverflow
let substringToLastIndexOfChar = text.lastIndexOfCharacter(".") // 17

PS Il est vraiment étrange que les développeurs soient obligés de faire face au String.Indexlieu de plaine Int. Pourquoi devrions-nous nous préoccuper de la Stringmécanique interne et pas seulement avoir des substring()méthodes simples ?

serg_zhd
la source
Vous ne devriez pas utiliser encodedOffsetvérifier ce commentaire et la bonne façon d'accomplir cela stackoverflow.com/questions/34540185/...
Leo Dabus
18

Je le ferais en utilisant un indice ( s[start..<end]):

Swift 3, 4, 5

let s = "www.stackoverflow.com"
let start = s.startIndex
let end = s.index(s.endIndex, offsetBy: -4)
let substring = s[start..<end] // www.stackoverflow
Marián Černý
la source
11

modifier / mettre à jour:

Dans Swift 4 ou version ultérieure (Xcode 10.0+), vous pouvez utiliser la nouvelle méthode BidirectionalCollection lastIndex (of :)

func lastIndex(of element: Element) -> Int?

let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
    let subString = string[..<lastIndex]  // "www.stackoverflow"
}
Leo Dabus
la source
C'est une excellente réponse, mais il semble qu'avec Swift 2, cette propriété a été déplacée vers NSUrl. Peut-être que cela aide les gens à lire ceci à l'avenir ...
chuky
8

Voici comment je fais. Vous pouvez le faire de la même manière ou utiliser ce code pour des idées.

let s = "www.stackoverflow.com"
s.substringWithRange(0..<s.lastIndexOf("."))

Voici les extensions que j'utilise:

import Foundation
extension String {

  var length: Int {
    get {
      return countElements(self)
    }
  }

  func indexOf(target: String) -> Int {
    var range = self.rangeOfString(target)
    if let range = range {
      return distance(self.startIndex, range.startIndex)
    } else {
      return -1
    }
  }

  func indexOf(target: String, startIndex: Int) -> Int {
    var startRange = advance(self.startIndex, startIndex)        
    var range = self.rangeOfString(target, options: NSStringCompareOptions.LiteralSearch, range: Range<String.Index>(start: startRange, end: self.endIndex))
    if let range = range {
      return distance(self.startIndex, range.startIndex)
    } else {
      return -1
    }
  }

  func lastIndexOf(target: String) -> Int {
    var index = -1
    var stepIndex = self.indexOf(target)
    while stepIndex > -1 {
      index = stepIndex
      if stepIndex + target.length < self.length {
        stepIndex = indexOf(target, startIndex: stepIndex + target.length)
      } else {
        stepIndex = -1
      }
    }
    return index
  } 

  func substringWithRange(range:Range<Int>) -> String {
    let start = advance(self.startIndex, range.startIndex)
    let end = advance(self.startIndex, range.endIndex)
    return self.substringWithRange(start..<end)
  }

}

Crédit albertbori / Extensions de cordes Swift communes

En général, je suis un fervent partisan des extensions, en particulier pour des besoins tels que la manipulation de chaînes, la recherche et le découpage.

joelparkerhenderson
la source
2
Je pense que c'est vraiment quelque chose qu'Apple devrait faire, pour améliorer l'API de String dans Swift.
skyline75489
2
Vous recherchez cette API. Apple Swift manque de beaucoup d'API de base. C'est un langage très complexe et incomplet. Swift est des conneries!
Loc
Voici une version bifurquée et mise à jour vers Swift 3 de la bibliothèque que vous référencez: github.com/iamjono/SwiftString
RenniePet
5

String a une fonction de sous-chaîne intégrée:

extension String : Sliceable {
    subscript (subRange: Range<String.Index>) -> String { get }
}

Si vous voulez "aller au premier index d'un caractère", vous pouvez obtenir la sous-chaîne en utilisant la find()fonction intégrée :

var str = "www.stackexchange.com"
str[str.startIndex ..< find(str, ".")!] // -> "www"

Pour trouver le dernier index, nous pouvons implémenter findLast().

/// Returns the last index where `value` appears in `domain` or `nil` if
/// `value` is not found.
///
/// Complexity: O(\ `countElements(domain)`\ )
func findLast<C: CollectionType where C.Generator.Element: Equatable>(domain: C, value: C.Generator.Element) -> C.Index? {
    var last:C.Index? = nil
    for i in domain.startIndex..<domain.endIndex {
        if domain[i] == value {
            last = i
        }
    }
    return last
}

let str = "www.stackexchange.com"
let substring = map(findLast(str, ".")) { str[str.startIndex ..< $0] } // as String?
// if "." is found, substring has some, otherwise `nil`

AJOUTÉE:

Peut-être que la BidirectionalIndexTypeversion spécialisée de findLastest plus rapide:

func findLast<C: CollectionType where C.Generator.Element: Equatable, C.Index: BidirectionalIndexType>(domain: C, value: C.Generator.Element) -> C.Index? {
    for i in lazy(domain.startIndex ..< domain.endIndex).reverse() {
        if domain[i] == value {
            return i
        }
    }
    return nil
}
Rintaro
la source
L'indice de String ne semble pas être disponible dans Swift 2.0, connaissez-vous un remplaçant?
Cory
Savez-vous comment puis-je contraindre Index à BidirectionalIndexType dans Swift 4 ou version ultérieure?
Leo Dabus
5

Vous pouvez utiliser ces extensions:

Swift 2.3

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

        func substringToIndex(index: Int) -> String
        {
            if (index < 0 || index > self.characters.count)
            {
                print("index \(index) out of bounds")
                return ""
            }
            return self.substringToIndex(self.startIndex.advancedBy(index))
        }

        func substringWithRange(start: Int, end: Int) -> String
        {
            if (start < 0 || start > self.characters.count)
            {
                print("start index \(start) out of bounds")
                return ""
            }
            else if end < 0 || end > self.characters.count
            {
                print("end index \(end) out of bounds")
                return ""
            }
            let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
            return self.substringWithRange(range)
        }

        func substringWithRange(start: Int, location: Int) -> String
        {
            if (start < 0 || start > self.characters.count)
            {
                print("start index \(start) out of bounds")
                return ""
            }
            else if location < 0 || start + location > self.characters.count
            {
                print("end index \(start + location) out of bounds")
                return ""
            }
            let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
            return self.substringWithRange(range)
        }
    }

Swift 3

extension String
{   
    func substring(from index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substring(from: self.characters.index(self.startIndex, offsetBy: index))
    }

    func substring(to index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
    }

    func substring(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: end)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }

    func substring(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }
}

Usage:

let string = "www.stackoverflow.com"        
let substring = string.substringToIndex(string.characters.count-4)
ChikabuZ
la source
5

Swift 4:

extension String {

    /// the length of the string
    var length: Int {
        return self.characters.count
    }

    /// Get substring, e.g. "ABCDE".substring(index: 2, length: 3) -> "CDE"
    ///
    /// - parameter index:  the start index
    /// - parameter length: the length of the substring
    ///
    /// - returns: the substring
    public func substring(index: Int, length: Int) -> String {
        if self.length <= index {
            return ""
        }
        let leftIndex = self.index(self.startIndex, offsetBy: index)
        if self.length <= index + length {
            return self.substring(from: leftIndex)
        }
        let rightIndex = self.index(self.endIndex, offsetBy: -(self.length - index - length))
        return self.substring(with: leftIndex..<rightIndex)
    }

    /// Get substring, e.g. -> "ABCDE".substring(left: 0, right: 2) -> "ABC"
    ///
    /// - parameter left:  the start index
    /// - parameter right: the end index
    ///
    /// - returns: the substring
    public func substring(left: Int, right: Int) -> String {
        if length <= left {
            return ""
        }
        let leftIndex = self.index(self.startIndex, offsetBy: left)
        if length <= right {
            return self.substring(from: leftIndex)
        }
        else {
            let rightIndex = self.index(self.endIndex, offsetBy: -self.length + right + 1)
            return self.substring(with: leftIndex..<rightIndex)
        }
    }
}

vous pouvez le tester comme suit:

    print("test: " + String("ABCDE".substring(index: 2, length: 3) == "CDE"))
    print("test: " + String("ABCDE".substring(index: 0, length: 3) == "ABC"))
    print("test: " + String("ABCDE".substring(index: 2, length: 1000) == "CDE"))
    print("test: " + String("ABCDE".substring(left: 0, right: 2) == "ABC"))
    print("test: " + String("ABCDE".substring(left: 1, right: 3) == "BCD"))
    print("test: " + String("ABCDE".substring(left: 3, right: 1000) == "DE"))

Consultez la bibliothèque https://gitlab.com/seriyvolk83/SwiftEx . Il contient ces méthodes et d'autres méthodes utiles.

Alexandre Volkov
la source
4

Voulez-vous obtenir une sous-chaîne d'une chaîne depuis l'index de début jusqu'au dernier index de l'un de ses caractères? Si tel est le cas, vous pouvez choisir l'une des méthodes Swift 2.0+ suivantes.

Méthodes qui nécessitent Foundation

Obtenez une sous-chaîne qui inclut le dernier index d'un caractère:

import Foundation

let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
    print(string.substringToIndex(rangeOfIndex.endIndex))
}

// prints "www.stackoverflow."

Obtenez une sous-chaîne qui n'inclut PAS le dernier index d'un caractère:

import Foundation

let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
    print(string.substringToIndex(rangeOfIndex.startIndex))
}

// prints "www.stackoverflow"

Si vous devez répéter ces opérations, l'extension Stringpeut être une bonne solution:

import Foundation

extension String {
    func substringWithLastInstanceOf(character: Character) -> String? {
        if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
            return self.substringToIndex(rangeOfIndex.endIndex)
        }
        return nil
    }
    func substringWithoutLastInstanceOf(character: Character) -> String? {
        if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
            return self.substringToIndex(rangeOfIndex.startIndex)
        }
        return nil
    }
}

print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))

/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/

Méthodes qui NE nécessitent PAS Foundation

Obtenez une sous-chaîne qui inclut le dernier index d'un caractère:

let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
    print(string[string.startIndex ..< reverseIndex.base])
}

// prints "www.stackoverflow."

Obtenez une sous-chaîne qui n'inclut PAS le dernier index d'un caractère:

let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
    print(string[string.startIndex ..< reverseIndex.base.advancedBy(-1)])
}

// prints "www.stackoverflow"

Si vous devez répéter ces opérations, l'extension Stringpeut être une bonne solution:

extension String {
    func substringWithLastInstanceOf(character: Character) -> String? {
        if let reverseIndex = characters.reverse().indexOf(".") {
            return self[self.startIndex ..< reverseIndex.base]
        }
        return nil
    }
    func substringWithoutLastInstanceOf(character: Character) -> String? {
        if let reverseIndex = characters.reverse().indexOf(".") {
            return self[self.startIndex ..< reverseIndex.base.advancedBy(-1)]
        }
        return nil
    }
}

print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))

/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/
Imanou Petit
la source
4

Voici un moyen simple et rapide d'obtenir une sous-chaîne si vous connaissez l'index:

let s = "www.stackoverflow.com"
let result = String(s.characters.prefix(17)) // "www.stackoverflow"

L'application ne plantera pas si votre index dépasse la longueur de la chaîne:

let s = "short"
let result = String(s.characters.prefix(17)) // "short"

Les deux exemples sont prêts pour Swift 3 .

Andrey Gordeev
la source
4

La seule chose qui ajoute du bruit est la répétition stringVar:

stringVar [ stringVar .index ( stringVar .startIndex, offsetBy: ...)

Dans Swift 4

Une extension peut en réduire une partie:

extension String {

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

Ensuite, utilisation:

let string = "abcde"

let to = string[..<string.index(at: 3)] // abc
let from = string[string.index(at: 3)...] // de

Il convient de noter que toet fromsont de type Substring(ou String.SubSequance). Ils n'allouent pas de nouvelles chaînes et sont plus efficaces pour le traitement.

Pour récupérer un Stringtype, il Substringdoit être renvoyé vers String:

let backToString = String(from)

C'est là qu'une chaîne est finalement allouée.

bauerMusique
la source
3
func substr(myString: String, start: Int, clen: Int)->String

{
  var index2 = string1.startIndex.advancedBy(start)
  var substring2 = string1.substringFromIndex(index2)
  var index1 = substring2.startIndex.advancedBy(clen)
  var substring1 = substring2.substringToIndex(index1)

  return substring1   
}

substr(string1, start: 3, clen: 5)
Professeur Oak
la source
3

Swift 3

let string = "www.stackoverflow.com"
let first3Characters = String(string.characters.prefix(3)) // www
let lastCharacters = string.characters.dropFirst(4) // stackoverflow.com (it would be a collection)

//or by index 
let indexOfFouthCharacter = olNumber.index(olNumber.startIndex, offsetBy: 4)
let first3Characters = olNumber.substring(to: indexOfFouthCharacter) // www
let lastCharacters = olNumber.substring(from: indexOfFouthCharacter) // .stackoverflow.com

Bon article pour comprendre, pourquoi avons-nous besoin de cela

Nik Kov
la source
2

J'ai étendu String avec deux méthodes de sous-chaîne. Vous pouvez appeler la sous-chaîne avec une plage from / to ou from / length comme ceci:

var bcd = "abcdef".substring(1,to:3)
var cde = "abcdef".substring(2,to:-2)
var cde = "abcdef".substring(2,length:3)

extension String {
  public func substring(from:Int = 0, var to:Int = -1) -> String {
    if to < 0 {
        to = self.length + to
    }
    return self.substringWithRange(Range<String.Index>(
        start:self.startIndex.advancedBy(from),
        end:self.startIndex.advancedBy(to+1)))
  }
  public func substring(from:Int = 0, length:Int) -> String {
    return self.substringWithRange(Range<String.Index>(
        start:self.startIndex.advancedBy(from),
        end:self.startIndex.advancedBy(from+length)))
  }
}
Andrewz
la source
self.length n'est plus disponible. Vous devez ajouter ceci dans l'extension (Andrewz, veuillez mettre à jour le code; je ne veux pas publier une autre réponse): public func length () -> Int {return self.lengthOfBytesUsingEncoding (NSUTF16StringEncoding)}
philippe
1

Swift 2.0 Le code ci-dessous est testé sur XCode 7.2. Veuillez vous référer à la capture d'écran ci-jointe en bas

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var mainText = "http://stackoverflow.com"

        var range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.startIndex.advancedBy(24))
        var subText = mainText.substringWithRange(range)


        //OR Else use below for LAST INDEX

        range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.endIndex)
        subText = mainText.substringWithRange(range)
    }
}
Chamath Jeevan
la source
1

Dans Swift 5

Nous avons besoin String.Indexau lieu d'une simple valeur Int pour représenter Index.

Rappelez-vous également que lorsque nous essayons d'obtenir des sous-chaînes de Swift String(type valeur), nous devons en fait itérer avec le Sequenceprotocole, qui renvoie le String.SubSequencetype au lieu du Stringtype.

Pour revenir à Stringpartir String.SubSequence, l' utilisationString(subString)

Exemple comme ci-dessous:

    let string = "https://stackoverflow.com"
    let firstIndex = String.Index(utf16Offset: 0, in: string)
    let lastIndex = String.Index(utf16Offset: 6, in: string)
    let subString = String(string[firstIndex...lastIndex])
macpandit
la source
0

Pour Swift 2.0 , c'est comme ça:

var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
mike.tihonchik
la source
Peut-être qu'ils l'ont changé, mais c'est «advancedBy» (notez le «d» à la fin de «advanced»)
Wedge Martin
0

J'ai modifié le post d'Andrewz pour le rendre compatible avec Swift 2.0 (et peut-être Swift 3.0). À mon humble avis, cette extension est plus facile à comprendre et similaire à ce qui est disponible dans d'autres langages (comme PHP).

extension String {

    func length() -> Int {
        return self.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)
    }
    func substring(from:Int = 0, to:Int = -1) -> String {
       var nto=to
        if nto < 0 {
            nto = self.length() + nto
        }
        return self.substringWithRange(Range<String.Index>(
           start:self.startIndex.advancedBy(from),
           end:self.startIndex.advancedBy(nto+1)))
    }
    func substring(from:Int = 0, length:Int) -> String {
        return self.substringWithRange(Range<String.Index>(
            start:self.startIndex.advancedBy(from),
            end:self.startIndex.advancedBy(from+length)))
    }
}
Philippe
la source
0

J'ai également construit une simple extension de chaîne pour Swift 4:

extension String {
    func subStr(s: Int, l: Int) -> String { //s=start, l=lenth
        let r = Range(NSRange(location: s, length: l))!
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        let indexRange = Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))

        return String(self[indexRange])
     }
}

Ainsi, vous pouvez facilement l'appeler comme ceci:

"Hallo world".subStr(s: 1, l: 3) //prints --> "all"
Marco Weber
la source
0

Essayez cette Int-basedsolution de contournement:

extension String {
    // start and end is included
    func intBasedSubstring(_ start: Int, _ end: Int) -> String {
        let endOffset: Int = -(count - end - 1)
        let startIdx = self.index(startIndex, offsetBy: start)
        let endIdx = self.index(endIndex, offsetBy: endOffset)
        return String(self[startIdx..<endIdx])
    }
}

Remarque: ce n'est qu'une pratique. Cela ne vérifie pas la frontière. Modifiez selon vos besoins.

steveluoxine
la source
-1

Voici un moyen simple d'obtenir une sous-chaîne dans Swift

import UIKit

var str = "Hello, playground" 
var res = NSString(string: str)
print(res.substring(from: 4))
print(res.substring(to: 10))
ZagorTeNej
la source
OP demande "Comment obtenir une sous-chaîne du début au dernier index du caractère" et non comment obtenir une sous-chaîne en utilisant des valeurs prédéfinies codées en dur.
Eric Aya
C'était un exemple original: convertir "www.stackoverflow.com" en "www.stackoverflow". Si vous voulez une sous-chaîne du début à la fin, il n'y a rien à faire, c'est-à-dire que le résultat est une chaîne d'entrée telle quelle. Veuillez restaurer l'utilité de la réponse ci-dessus.
ZagorTeNej