Swift: come ottenere la sottostringa dall'inizio all'ultimo indice di carattere


110

Voglio imparare il modo migliore / più semplice per trasformare una stringa in un'altra stringa ma con solo un sottoinsieme, partendo dall'inizio e andando all'ultimo indice di un carattere.

Ad esempio, converti "www.stackoverflow.com" in "www.stackoverflow". Quale snippet di codice lo farebbe ed essendo il più veloce? (Spero che questo non porti un dibattito, ma non riesco a trovare una buona lezione su come gestire le sottostringhe in Swift.

Risposte:


202

Accesso solo all'indietro

Il modo migliore è usare substringToIndexcombinato con la endIndexproprietà e la advancefunzione globale.

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substringToIndex(index1)

Alla ricerca di una corda che inizi dal retro

Usa rangeOfStringe imposta optionssu.BackwardsSearch

var string2 = "www.stackoverflow.com"

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

var substring2 = string2.substringToIndex(index2!)

Nessuna estensione, puro idiomatico Swift

Swift 2.0

advancefa ora parte di Indexed è chiamato advancedBy. Ti piace:

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substringToIndex(index1)

Swift 3.0

Non puoi chiamare advancedBya Stringperché ha elementi di dimensioni variabili. Devi usare index(_, offsetBy:).

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substring(to: index1)

Molte cose sono state rinominate. I casi sono scritti in camelCase, è startIndexdiventato lowerBound.

var string2 = "www.stackoverflow.com"

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

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

Inoltre, non consiglierei lo scartamento forzato index2. È possibile utilizzare l'associazione facoltativa o map. Personalmente preferisco usare map:

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

Swift 4

La versione Swift 3 è ancora valida, ma ora puoi utilizzare pedici con intervalli di indici:

let string1 = "www.stackoverflow.com"

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

let substring1 = string1[..<index1]

Il secondo approccio rimane invariato:

let string2 = "www.stackoverflow.com"

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

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

1
Grazie @ fpg1503. Questo è il tipo di risposta che stavo cercando di trovare. Le altre risposte mi hanno insegnato o mi hanno ricordato le caratteristiche della lingua, ma questo è il modo in cui userò per risolvere il mio problema.
Jason Hocker

1
Utilizzando Swift 2.0, string1.endIndex.advancedBy(-4)sta funzionando per me invece diadvance
Alex Koshy

92
Non c'è davvero alcun modo per farlo semplicemente?
devios1

12
@ devios tutto vero. Sono grato per Swift rispetto a Objective-C, ma IMHO le preoccupazioni che portano a questo codice follemente imbarazzante sono irrilevanti per il 99% del codice e dei programmatori là fuori. Peggio ancora, finiremo per scrivere noi stessi estensioni di cattiva convenienza. Se gli sviluppatori regolari non riescono a comprendere queste preoccupazioni di livello superiore, sono IL MENO in grado di scrivere un'API ad-hoc per affrontare le preoccupazioni pedonali con cui realizziamo software. La tendenza a convertirsi a NSStringè ovviamente negativa, perché alla fine tutti noi vogliamo allontanarci dalle classi della Fondazione (legacy). Quindi .... più farneticazioni!
Dan Rosenstark

2
In Swift 4, puoi farlo string1[..<index1]. Non ce n'è bisogno string1.startIndex.
bauerMusic

26

Swift 3, XCode 8

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

Dal momento che advancedBy(Int)è sparito da quando Swift 3 usa Stringil metodo di index(String.Index, Int). Dai un'occhiata a questa Stringestensione con sottostringa e amici:

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

Estensione AGGIORNATA per 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)
    }
}

Uso:

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 È davvero strano che gli sviluppatori siano costretti a confrontarsi String.Indexinvece che a pianificarli Int. Perché dovremmo preoccuparci della Stringmeccanica interna e non avere solo substring()metodi semplici ?


Si consiglia di non utilizzare encodedOffsetcontrollare questo commento e il modo corretto di realizzare questo stackoverflow.com/questions/34540185/...
Leo Dabus

18

Lo farei usando un subscript ( 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

11

Modifica / aggiornamento:

In Swift 4 o versioni successive (Xcode 10.0+) puoi utilizzare il nuovo metodo BidirectionalCollection lastIndex (di :)

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

let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
    let subString = string[..<lastIndex]  // "www.stackoverflow"
}

Questa è un'ottima risposta, ma sembra che con Swift 2 questa proprietà sia stata spostata in NSUrl. Forse questo aiuta le persone a leggere questo in futuro ...
Chuky

8

Ecco come lo faccio. Puoi farlo allo stesso modo o usare questo codice per le idee.

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

Ecco le estensioni che utilizzo:

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

}

Credito albertbori / Common Swift String Extensions

In generale sono un forte sostenitore delle estensioni, specialmente per esigenze come la manipolazione delle stringhe, la ricerca e lo slicing.


2
Penso che questi siano davvero qualcosa che Apple dovrebbe fare, per migliorare l'API di String in Swift.
skyline75489

2
Alla ricerca di questa API. Ad Apple Swift mancano molte API di base. È un linguaggio molto complesso e anche non completo. Swift è una stronzata!
Loc

Ecco una versione biforcuta e aggiornata di Swift 3 della libreria a cui fai riferimento: github.com/iamjono/SwiftString
RenniePet

5

String ha una funzione di sottostringa incorporata:

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

Se quello che vuoi è "andare al primo indice di un carattere", puoi ottenere la sottostringa usando la find()funzione incorporata :

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

Per trovare l' ultimo indice, possiamo implementare 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`

AGGIUNTO:

Forse, la BidirectionalIndexTypeversione specializzata di findLastè più veloce:

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
}

L'indice di String non sembra essere disponibile in Swift 2.0, conosci un sostituto?
Cory

Sai come posso vincolare Index su BidirectionalIndexType in Swift 4 o versioni successive?
Leo Dabus

5

Puoi utilizzare queste estensioni:

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

Uso:

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

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

puoi testarlo come segue:

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

Controlla la libreria https://gitlab.com/seriyvolk83/SwiftEx . Contiene questi e altri metodi utili.


4

Vuoi ottenere una sottostringa di una stringa dall'indice iniziale all'ultimo indice di uno dei suoi caratteri? In tal caso, puoi scegliere uno dei seguenti metodi Swift 2.0+.

Metodi che richiedono Foundation

Ottieni una sottostringa che include l'ultimo indice di un carattere:

import Foundation

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

// prints "www.stackoverflow."

Ottieni una sottostringa che NON include l'ultimo indice di un carattere:

import Foundation

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

// prints "www.stackoverflow"

Se è necessario ripetere queste operazioni, l'estensione Stringpuò essere una buona soluzione:

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")
*/

Metodi che NON richiedono Foundation

Ottieni una sottostringa che include l'ultimo indice di un carattere:

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

// prints "www.stackoverflow."

Ottieni una sottostringa che NON include l'ultimo indice di un carattere:

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

// prints "www.stackoverflow"

Se è necessario ripetere queste operazioni, l'estensione Stringpuò essere una buona soluzione:

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")
*/

4

Ecco un modo semplice e breve per ottenere una sottostringa se conosci l'indice:

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

L'app non andrà in crash se il tuo indice supera la lunghezza della stringa:

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

Entrambi gli esempi sono pronti per Swift 3 .


4

L'unica cosa che aggiunge rumore è il ripetersi stringVar :

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

In Swift 4

Un'estensione può ridurre parte di ciò:

extension String {

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

Quindi, utilizzo:

let string = "abcde"

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

Va notato che toe fromsono di tipo Substring(o String.SubSequance). Non assegnano nuove stringhe e sono più efficienti per l'elaborazione.

Per recuperare un Stringtipo, è Substringnecessario eseguire nuovamente il cast in String:

let backToString = String(from)

Qui è dove una stringa viene finalmente allocata.


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)

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

Buon articolo per capire, perché ne abbiamo bisogno


2

Ho esteso String con due metodi di sottostringa. Puoi chiamare sottostringa con un intervallo da / a o da / lunghezza in questo modo:

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

self.length non è più disponibile. Devi aggiungerlo nell'estensione (Andrewz, aggiorna il codice; non voglio pubblicare un'altra risposta): public func length () -> Int {return self.lengthOfBytesUsingEncoding (NSUTF16StringEncoding)}
philippe

1

Swift 2.0 Il codice seguente è testato su XCode 7.2. Fare riferimento allo screenshot allegato in basso

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

1

In Swift 5

Abbiamo bisogno String.Indexinvece del semplice valore Int per rappresentare Index.

Ricorda inoltre, quando proviamo a ottenere subString da Swift String(tipo di valore), in realtà dobbiamo iterare con Sequenceprotocollo, che restituisce String.SubSequencetipo invece di Stringtipo.

Per tornare Stringda String.SubSequence, usaString(subString)

Esempio come sotto:

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

0

Per Swift 2.0 , è così:

var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)

Forse l'hanno cambiato, ma è "advancedBy" (nota la "d" alla fine di "advanced")
Wedge Martin

0

Ho modificato il post di andrewz per renderlo compatibile con Swift 2.0 (e forse Swift 3.0). A mio modesto parere, questa estensione è più facile da capire e simile a ciò che è disponibile in altre lingue (come 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)))
    }
}

0

Creo anche una semplice estensione String per 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])
     }
}

Quindi puoi facilmente chiamarlo in questo modo:

"Hallo world".subStr(s: 1, l: 3) //prints --> "all"

0

Prova questa Int-basedsoluzione alternativa:

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

Nota: è solo una pratica. Non controlla il confine. Modifica in base alle tue esigenze.


-1

Ecco un modo semplice per ottenere sottostringhe in Swift

import UIKit

var str = "Hello, playground" 
var res = NSString(string: str)
print(res.substring(from: 4))
print(res.substring(to: 10))

OP chiede "Come ottenere la sottostringa dall'inizio all'ultimo indice di carattere" non come ottenere la sottostringa utilizzando valori hardcoded predefiniti.
Eric Aya

Questo era un esempio originale: converti "www.stackoverflow.com" in "www.stackoverflow". Se vuoi una sottostringa dall'inizio alla fine, non c'è niente da fare, cioè il risultato è una stringa di input così com'è. Ripristina l'utilità della risposta precedente.
ZagorTeNej
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.