Come si usa String.substringWithRange? (o come funzionano gli intervalli in Swift?)


266

Non sono ancora stato in grado di capire come ottenere una sottostringa di a Stringin Swift:

var str =Hello, playground”
func test(str: String) -> String {
 return str.substringWithRange( /* What goes here? */ )
}
test (str)

Non sono in grado di creare un intervallo in Swift. Il completamento automatico nel Playground non è molto utile - questo è ciò che suggerisce:

return str.substringWithRange(aRange: Range<String.Index>)

Non ho trovato nulla nella libreria di riferimento standard di Swift che mi aiuti. Ecco un'altra ipotesi selvaggia:

return str.substringWithRange(Range(0, 1))

E questo:

let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)

Ho visto altre risposte ( Trovare l'indice di carattere in Swift String ) che sembrano suggerire che dato che Stringè un tipo bridge per NSString, i "vecchi" metodi dovrebbero funzionare, ma non è chiaro come - ad esempio, neanche questo funziona ( non sembra essere una sintassi valida):

let x = str.substringWithRange(NSMakeRange(0, 3))

Pensieri?


Cosa intendi quando dici che l'ultimo esempio non funziona? Provoca un errore o restituisce un valore imprevisto?
67cherries

Please dupe rdar: // 17158813 richiesta notazione in abbonamento openradar.appspot.com/radar?id=6373877630369792
Rob Napier

Risposte:


259

È possibile utilizzare il metodo substringWithRange. Ci vuole un inizio e una fine String.Index.

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"

Per modificare l'indice di inizio e fine, utilizzare advancedBy (n).

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"

Puoi anche usare il metodo NSString con NSRange, ma devi assicurarti di utilizzare un NSString come questo:

let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))

Nota: come menzionato JanX2, questo secondo metodo non è sicuro con le stringhe unicode.


5
Si. Per ora continuerei a fare il ponte su NSString quando necessario. Sembra che Swift's String sia ancora incompleto
Connor

14
Questo non è sicuro! Si presuppone che gli indici in String e NSString siano intercambiabili. Questo non è il caso. Gli indici in una stringa si riferiscono a punti di codice Unicode mentre gli indici in una stringa NSS si riferiscono a unità di codice UTF-16! Provalo con le emoji.
JanX2

3
Si noti che gli indici in una stringa NON fanno più riferimento ai punti di codice Unicode. Considerali come riferimenti a personaggi percepiti dall'utente.
JanX2,

2
Quindi qual è la risposta giusta qui? Chiamare advancesignifica che dobbiamo iterare completamente attraverso una stringa possibilmente lunga. Ma formare un NSRange e usare esplicitamente NSString è pericoloso? Cos'è rimasto?
opaco

1
Grazie, m8. Questa transizione verso Swift è un po 'disordinata dopo solo 4 anni con Objective-C.
Felipe,

162

Swift 2

Semplice

let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"

Swift 3

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)

str[startIndex...endIndex]       // "Strin"
str.substring(to: startIndex)    // "My "
str.substring(from: startIndex)  // "String"

Swift 4

substring(to:)e substring(from:)sono deprecati in Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"

2
QUESTO. Così confuso che devi trovare il tuo indice prima di poterlo utilizzare. Non ho idea del perché mi ci sia voluto tanto tempo per realizzarlo, ma grazie per il tuo contributo al genere umano.
Warpzit,

1
In swift 4 le operazioni di sottostringa restituiscono un'istanza del tipo Sottostringa, anziché Stringa. È necessario convertire il risultato in una stringa per l'archiviazione a lungo termine. let newString = String (sottostringa)
phnmnn

43

NOTA: @airspeedswift fa alcuni punti molto approfonditi sui compromessi di questo approccio, in particolare gli impatti nascosti sulle prestazioni. Le stringhe non sono semplici animali e arrivare a un determinato indice può richiedere O (n) tempo, il che significa che un ciclo che utilizza un pedice può essere O (n ^ 2). Sei stato avvertito.

Hai solo bisogno di aggiungere una nuova subscriptfunzione che prende un intervallo e usa advancedBy()per camminare dove vuoi:

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(Questo dovrebbe sicuramente essere parte della lingua. Per favore dupe rdar: // 17158813 )

Per divertimento, puoi anche aggiungere un +operatore agli indici:

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(Non so ancora se questo dovrebbe essere parte della lingua o no.)


2
Probabilmente dovremmo lavorare il più possibile con String.Index anziché con gli indici interi per motivi di prestazioni. Ogni conversione da un indice intero in String.Index deve elaborare la stringa per cercare.
JanX2

11
@AndrewDunn Questa non è ottimizzazione prematura. Ogni conversione da un indice intero in String.Index è O (n), non O (1)! Si prega di leggere i commenti advance<T>(…)nello Swiftspazio dei nomi.
JanX2

1
L'intera implementazione di String viene eseguita utilizzando String.Index. In questo caso non è tanto ottimizzazione quanto sta mantenendo tutto semplice. Dover destreggiarsi tra int e String.Index avanti e indietro ovunque porterà a un casino.
Chakrit,

@chakrit Solo se gli indici che devi usare non sono già numeri interi (anziché essere String.Indexes), come spesso accade. Quindi puoi solo desiderare che tutti quei metodi di gestione delle stringhe funzionino con Ints. E sei costretto a convertirlo in ciò String.Indexesche porta al disordine che hai citato.
Rasto,

Il lettore interessato dovrebbe dare un'occhiata a ExSwift github.com/pNre/ExSwift
AsTeR

42

Al momento sto scrivendo, nessuna estensione è perfettamente compatibile con Swift 4.2 , quindi eccone una che copre tutte le esigenze a cui potrei pensare:

extension String {
    func substring(from: Int?, to: Int?) -> String {
        if let start = from {
            guard start < self.count else {
                return ""
            }
        }

        if let end = to {
            guard end >= 0 else {
                return ""
            }
        }

        if let start = from, let end = to {
            guard end - start >= 0 else {
                return ""
            }
        }

        let startIndex: String.Index
        if let start = from, start >= 0 {
            startIndex = self.index(self.startIndex, offsetBy: start)
        } else {
            startIndex = self.startIndex
        }

        let endIndex: String.Index
        if let end = to, end >= 0, end < self.count {
            endIndex = self.index(self.startIndex, offsetBy: end + 1)
        } else {
            endIndex = self.endIndex
        }

        return String(self[startIndex ..< endIndex])
    }

    func substring(from: Int) -> String {
        return self.substring(from: from, to: nil)
    }

    func substring(to: Int) -> String {
        return self.substring(from: nil, to: to)
    }

    func substring(from: Int?, length: Int) -> String {
        guard length > 0 else {
            return ""
        }

        let end: Int
        if let start = from, start > 0 {
            end = start + length - 1
        } else {
            end = length - 1
        }

        return self.substring(from: from, to: end)
    }

    func substring(length: Int, to: Int?) -> String {
        guard let end = to, end > 0, length > 0 else {
            return ""
        }

        let start: Int
        if let end = to, end - length > 0 {
            start = end - length + 1
        } else {
            start = 0
        }

        return self.substring(from: start, to: to)
    }
}

E poi, puoi usare:

let string = "Hello,World!"

string.substring(from: 1, to: 7)ti prende: ello,Wo

string.substring(to: 7)ti prende: Hello,Wo

string.substring(from: 3)ti prende: lo,World!

string.substring(from: 1, length: 4)ti prende: ello

string.substring(length: 4, to: 7)ti prende: o,Wo

Aggiornato substring(from: Int?, length: Int)per supportare a partire da zero.


In che modo gestisce emoji e cluster grapheme estesi? (Dovrei provarlo da solo, ma al momento non è conveniente.)
Suragch,

2
@Suragch Lo gestisce bene: "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)ci dà:o😇😍😘😎📸📀💾∝ℵℶ
invernale

Questi sembrano personaggi normali, però. Prova a usare emoji come 👩‍👩‍👧‍👦 o 🇨🇦🇺🇸🇲🇽
Supuhstar

31

SWIFT 2.0

semplice:

let myString = "full text container"
let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful

SWIFT 3.0

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

SWIFT 4.0

Le operazioni di sottostringa restituiscono un'istanza del tipo Sottostringa, anziché Stringa.

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

// Convert the result to a String for long-term storage.
let newString = String(substring)

4
Non più compatibile con Swift 3 a partire da Xcode 8 beta 6, purtroppo
Ben Morrow

1
Per me va bene. Xcode 8, Swift 3. Non beta su Mac OS Sierra. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jose Ramirez,

18

È molto più semplice di una qualsiasi delle risposte qui, una volta trovata la sintassi giusta.

Voglio portare via il [e]

let myString = "[ABCDEFGHI]"
let startIndex = advance(myString.startIndex, 1) //advance as much as you like
let endIndex = advance(myString.endIndex, -1)
let range = startIndex..<endIndex
let myNewString = myString.substringWithRange( range )

il risultato sarà "ABCDEFGHI" in cui è possibile utilizzare anche startIndex e endIndex

let mySubString = myString.substringFromIndex(startIndex)

e così via!

PS: Come indicato nelle osservazioni, ci sono alcune modifiche alla sintassi in swift 2 che viene fornito con xcode 7 e iOS9!

Si prega di guardare questa pagina


Sì, ho avuto gli stessi problemi con il debugger che non mostrava la stringa corretta più volte?
user1700737

ho una stringa come questa / Data (147410000000) /. Come posso ottenere valore invece di specificare l'indice. Ho bisogno di ottenere il valore utilizzando rangeOfString ("(") e rangeOfString (")"). Il risultato dovrebbe essere 147410000000. Zappa posso ottenerlo
iPhone Guy,

Non è così difficile: var str = "/ Date (147410000000) /." var range = str.rangeOfString ("(") !. endIndex .. <str.rangeOfString (")") !. startIndex let myNewString = str.substringWithRange (range)
user1700737

4
da quando la advance(myString.endIndex, -1)sintassi Xcode 7 beta 6 è cambiata inmyString.endIndex.advancedBy(-1)
l --marc l

16

Ad esempio per trovare il nome (fino al primo spazio) nel mio nome completo:

let name = "Joris Kluivers"

let start = name.startIndex
let end = find(name, " ")

if end {
    let firstName = name[start..end!]
} else {
    // no space found
}

starte endsono di tipo String.Indexqui e vengono utilizzati per creare un Range<String.Index>e utilizzato nell'accessorio di sottoscrizione (se viene trovato uno spazio nella stringa originale).

È difficile creare un String.Indexdirettamente da una posizione intera come utilizzato nel post di apertura. Questo perché nel mio nome ogni personaggio avrebbe la stessa dimensione in byte. Ma i caratteri che usano accenti speciali in altre lingue avrebbero potuto usare molti più byte (a seconda della codifica utilizzata). Quindi a quale byte dovrebbe riferirsi l'intero?

È possibile crearne uno nuovo String.Indexda uno esistente utilizzando i metodi succe predciò assicurerà che il numero corretto di byte venga saltato per arrivare al punto di codice successivo nella codifica. Tuttavia, in questo caso è più semplice cercare l'indice del primo spazio nella stringa per trovare l'indice finale.


16

Poiché String è un tipo di ponte per NSString, i metodi "vecchi" dovrebbero funzionare, ma non è chiaro come - ad esempio, neanche questo funziona (non sembra essere una sintassi valida):

 let x = str.substringWithRange(NSMakeRange(0, 3))

Per me, questa è la parte davvero interessante della tua domanda. String è colmato di NSString, in modo più metodi NSString fanno lavorare direttamente su una stringa. Puoi usarli liberamente e senza pensare. Quindi, ad esempio, funziona esattamente come ti aspetti:

// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")

Ma, come spesso accade, "Ho fatto funzionare il mio mojo ma non funziona su di te." Ti è capitato di scegliere uno dei rari casi in cui esiste un metodo Swift identicamente parallelo e, in un caso del genere, il metodo Swift oscura il metodo Objective-C. Quindi, quando dici str.substringWithRange, Swift pensa che intendi il metodo Swift piuttosto che il metodo NSString - e poi sei bucato, perché il metodo Swift si aspetta un Range<String.Index>, e non sai come crearne uno.

La semplice via d'uscita è impedire a Swift di oscurare in questo modo, lanciando esplicitamente:

let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))

Si noti che qui non è richiesto alcun lavoro extra significativo. "Cast" non significa "converti"; la stringa è effettivamente una stringa NSS. Stiamo solo dicendo a Swift come guardare questa variabile ai fini di questa riga di codice.

La parte davvero strana di tutto ciò è che il metodo Swift, che causa tutti questi problemi, non è documentato. Non ho idea di dove sia definito; non è nell'intestazione NSString e non è nemmeno nell'intestazione Swift.


Tuttavia, suggerisco di presentare un bug. La mela dovrebbe "pescare o tagliare esche" - o darci un modo per costruire un Range<String.Index>, o toglierci questo metodo senza documenti.
matt

Accidenti - questo è utile. Nonostante ciò che dice la documentazione, non ho capito cosa non andava fino a quando non ho letto questo. Ora ordinato :)
Jon M

13

Nel nuovo Xcode 7.0 utilizzare

//: Playground - noun: a place where people can play

import UIKit

var name = "How do you use String.substringWithRange?"
let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10)
name.substringWithRange(range)

//OUT:

inserisci qui la descrizione dell'immagine


2
.advancedBy(0) non è necessario per startIndex.
Mat0,

12

La risposta breve è che questo è davvero difficile in Swift in questo momento. La mia impressione è che Apple abbia ancora molto lavoro da fare sui metodi di praticità per cose come questa.

String.substringWithRange()si aspetta un Range<String.Index>parametro e, per quanto ne so, non esiste un metodo generatore per il String.Indextipo. Puoi recuperare String.Indexvalori da aString.startIndexe aString.endIndexe chiamare .succ()o .pred()su di essi, ma questa è follia.

Che ne dici di un'estensione sulla classe String che impiega dei vecchi vecchi Int?

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let subStart = advance(self.startIndex, r.startIndex, self.endIndex)
            let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex)
            return self.substringWithRange(Range(start: subStart, end: subEnd))
        }
    }
    func substring(from: Int) -> String {
        let end = countElements(self)
        return self[from..<end]
    }
    func substring(from: Int, length: Int) -> String {
        let end = from + length
        return self[from..<end]
    }
}

let mobyDick = "Call me Ishmael."
println(mobyDick[8...14])             // Ishmael

let dogString = "This 🐶's name is Patch."
println(dogString[5..<6])               // 🐶
println(dogString[5...5])              // 🐶
println(dogString.substring(5))        // 🐶's name is Patch.
println(dogString.substring(5, length: 1))   // 🐶

Aggiornamento: Swift beta 4 risolve i problemi seguenti!

Allo stato attuale [in beta 3 e precedenti], anche le stringhe native di Swift hanno dei problemi con la gestione dei caratteri Unicode. L'icona del cane sopra ha funzionato, ma non segue:

let harderString = "1:1️⃣"
for character in harderString {
    println(character)
}

Produzione:

1
:
1
️
⃣

1
È strano, le classi Swift di base sembrano non avere molte funzioni di base. Non riesco a pensare che Apple voglia che ci riferiamo continuamente alle lezioni della Fondazione per svolgere compiti semplici.
bluedevil2k,

1
Totalmente. Tieni presente che Swift è stato sostanzialmente sviluppato al buio e ognuno ha una diversa definizione di "compiti semplici" - Scommetto che vediamo una rapida iterazione su questi temi.
Nate Cook,

@ JanX2 - Grazie, hai perfettamente ragione. Il ponte NSStringcontinuo con me mi ha fatto pensare che stavo usando solo Stringmetodi nativi di Swift , dal momento che non stavo usando alcuna myString as NSStringchiamata.
Nate Cook,

In questo momento ci sono anche alcuni bug Unicode nella gestione delle stringhe native di Swift: vedi la mia nota alla fine.
Nate Cook,

@NateCook Puoi per favore inviare un radar per quel problema?
JanX2

11

È possibile utilizzare queste estensioni per migliorare substringWithRange

Swift 2.3

extension String
{   
    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(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 str = "Hello, playground"

let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground

7

Codice di esempio per come ottenere la sottostringa in Swift 2.0

(i) Sottostringa dall'indice iniziale

Ingresso:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)

Produzione:-

Swift is very powerful language!
Swift

(ii) Sottostringa da un indice particolare

Ingresso:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)

Produzione:-

Swift is very powerful language!
is

Spero che ti possa aiutare!


7

Soluzione semplice con poco codice.

Crea un'estensione che include una sottostringa di base che ha quasi tutte le altre lingue:

extension String {
    func subString(start: Int, end: Int) -> String {
        let startIndex = self.index(self.startIndex, offsetBy: start)
        let endIndex = self.index(startIndex, offsetBy: end)

        let finalString = self.substring(from: startIndex)
        return finalString.substring(to: endIndex)
    }
}

Chiamalo semplicemente con

someString.subString(start: 0, end: 6)

1
Il parametro 'end' in realtà significa lunghezza qui, quindi penso che dovrebbe essere rinominato in questo.
Jovan Jovanovski,

Penso che usare la lunghezza sia piuttosto confuso. In realtà è la 'fine' di dove vorresti che fosse la sottostringa, non la lunghezza effettiva del risultato delle sottostringhe.
Oliver Dixon,

6

Funziona nel mio parco giochi :)

String(seq: Array(str)[2...4])

In realtà questo è più efficiente che chiamareadvance
Erik Aigner

2
Non funziona nel mio parco giochi Xcode 7 (Swift 2), ma questo ... 'var str = "Hello, playground"' String (Array (str.characters) [7]) // "p" String (Array ( str.characters) [7 ... 10]) // "play" String (Array (str.characters) [7 .. <10]) // "pla"
Vince O'Sullivan,

6

Aggiornato per Xcode 7. Aggiunge l'estensione String:

Uso:

var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck

Implementazione:

extension String {

    /**
     Subscript to allow for quick String substrings ["Hello"][0...1] = "He"
     */
    subscript (r: Range<Int>) -> String {
        get {
            let start = self.startIndex.advancedBy(r.startIndex)
            let end = self.startIndex.advancedBy(r.endIndex - 1)
            return self.substringWithRange(start..<end)
        }
    }

}

4

prova questo nel parco giochi

var str:String = "Hello, playground"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))

ti darà "ciao, p"

Tuttavia, dove questo diventa davvero interessante è che se si rende l'ultimo indice più grande della stringa nel parco giochi, mostrerà tutte le stringhe definite dopo str: o

Range () sembra essere una funzione generica, quindi deve conoscere il tipo con cui ha a che fare.

Devi anche dargli la stringa attuale che ti interessa nei campi da gioco in quanto sembra contenere tutte le punture in sequenza una dopo l'altra con il loro nome variabile in seguito.

Così

var str:String = "Hello, playground"

var str2:String = "I'm the next string"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49))

"ello, playground str Sono la stringa successiva str2 "

funziona anche se str2 è definito con let

:)


Sono d'accordo che è dettagliato rispetto all'Obiettivo-C, tuttavia si adatta tutto su una riga che è un vantaggio.
Peter Roberts,

Bene c'è ancora una riga mancante che in realtà stampa la sottostringa dato l'intervallo che hai calcolato. Mi piacciono alcune delle altre soluzioni che creano estensioni di classe String usando la tua logica, ma in un'estensione. Questa è in definitiva la soluzione con cui sono andato.
Roderic Campbell,

Hanno corretto il bug in cui puoi andare oltre la fine della stringa. Ora puoi solo inserire un valore fino a str.endIndex
Peter Roberts,

4

Rob Napier aveva già dato una risposta fantastica usando il pedice. Ma ho avvertito uno svantaggio in quanto non esiste un controllo per le condizioni fuori limite. Questo può tendere a bloccarsi. Quindi ho modificato l'estensione ed eccola qui

extension String {
    subscript (r: Range<Int>) -> String? { //Optional String as return value
        get {
            let stringCount = self.characters.count as Int
            //Check for out of boundary condition
            if (stringCount < r.endIndex) || (stringCount < r.startIndex){
                return nil
            }
            let startIndex = self.startIndex.advancedBy(r.startIndex)

            let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

Uscita di seguito

var str2 = "Hello, World"

var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil

Quindi suggerisco di controllare sempre se lasciato

if let string = str[0...5]
{
    //Manipulate your string safely
}

C'è un bug lì - endIndex dovrebbe essere startIndex avanzato solo da endIndex, non dalla distanza tra gli indici.
Aviad Ben Dov,

3

In Swift3

Ad esempio: una variabile "Duke James Thomas", dobbiamo ottenere "James".

let name = "Duke James Thomas"
let range: Range<String.Index> = name.range(of:"James")!
let lastrange: Range<String.Index> = img.range(of:"Thomas")!
var middlename = name[range.lowerBound..<lstrange.lowerBound]
print (middlename)

2

Prendendo una pagina da Rob Napier, ho sviluppato queste estensioni di stringa comuni , due delle quali sono:

subscript (r: Range<Int>) -> String
{
    get {
        let startIndex = advance(self.startIndex, r.startIndex)
        let endIndex = advance(self.startIndex, r.endIndex - 1)

        return self[Range(start: startIndex, end: endIndex)]
    }
}

func subString(startIndex: Int, length: Int) -> String
{
    var start = advance(self.startIndex, startIndex)
    var end = advance(self.startIndex, startIndex + length)
    return self.substringWithRange(Range<String.Index>(start: start, end: end))
}

Uso:

"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"

È possibile utilizzare Rangeanziché Range<String.Index>grazie all'inferenza del tipo.
Dan Rosenstark,

2

Ecco come ottenere un intervallo da una stringa:

var str = "Hello, playground"

let startIndex = advance(str.startIndex, 1)
let endIndex = advance(startIndex, 8)
let range = startIndex..<endIndex
let substr = str[range] //"ello, pl"

Il punto chiave è che stai passando un intervallo di valori di tipo String.Index (questo è ciò che restituisce anticipo) invece di numeri interi.

Il motivo per cui questo è necessario è che le stringhe in Swift non hanno accesso casuale (a causa della lunghezza variabile dei caratteri Unicode). Inoltre non puoi farlo str[1]. String.Index è progettato per funzionare con la loro struttura interna.

Puoi creare un'estensione con un pedice, che fa questo per te, quindi puoi semplicemente passare un intervallo di numeri interi (vedi ad esempio la risposta di Rob Napier ).


2

Ho provato a trovare qualcosa di Pythonic.

Tutti gli abbonamenti qui sono fantastici, ma le volte in cui ho davvero bisogno di qualcosa di semplice è di solito quando voglio contare da dietro, ad es string.endIndex.advancedBy(-1)

Supporta nilvalori, sia per l'indice iniziale che per quello finale, dove nilsignificherebbe indice a 0 per inizio, string.characters.countper fine.

extension String {
    var subString: (Int?) -> (Int?) -> String {
        return { (start) in
            { (end) in
                let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
                let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)

                return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
            }
        }
    }
}

let dog = "Dog‼🐶"
print(dog.subString(nil)(-1)) // Dog!!

MODIFICARE

Una soluzione più elegante:

public extension String {
    struct Substring {
        var start: Int?
        var string: String

        public subscript(end: Int?) -> String {
            let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0)
            let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count)

            return startIndex > endIndex ? "" : string.substringWithRange(startIndex ..< endIndex)
        }
    }

    public subscript(start: Int?) -> Substring {
        return Substring(start: start, string: self)
    }
}

let dog = "Dog‼🐶"
print(dog[nil][-1]) // Dog!!

1

Prima crea l'intervallo, quindi la sottostringa. Puoi usare la fromIndex..<toIndexsintassi in questo modo:

let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)

1

ecco un esempio per ottenere solo l'ID video .ie (6oL687G0Iso) dall'intero URL in modo rapido

let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)

1
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Campione completo che puoi vedere qui



0

Bene, ho avuto lo stesso problema e risolto con la funzione "bridgeToObjectiveC ()":

var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!

Si noti che nell'esempio, substringWithRange in combinazione con NSMakeRange prende la parte della stringa che inizia all'indice 6 (carattere "W") e termina all'indice 6 + 6 posizioni in avanti (carattere "!")

Saluti.


Lo odio, ma è l'unica cosa che sembra funzionare per me in Beta 4.
Roderic Campbell,

0

Puoi utilizzare uno qualsiasi dei metodi di sottostringa in un'estensione Swift String che ho scritto https://bit.ly/JString .

var string = "hello"
var sub = string.substringFrom(3) // or string[3...5]
println(sub)// "lo"

0

Se ne hai uno NSRange, il bridge NSStringfunziona perfettamente. Ad esempio, stavo facendo un po 'di lavoro con UITextFieldDelegatee volevo rapidamente calcolare il nuovo valore di stringa quando mi chiedeva se doveva sostituire l'intervallo.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    println("Got new string: ", newString)
}

0

Estensione semplice per String:

extension String {

    func substringToIndex(index: Int) -> String {
        return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
    }
}

0

Se non ti interessano le prestazioni ... questa è probabilmente la soluzione più concisa in Swift 4

extension String {
    subscript(range: CountableClosedRange<Int>) -> String {
        return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
            .reduce(""){$0 + String($1.element)}
    }
}

Ti consente di fare qualcosa del genere:

let myStr = "abcd"
myStr[0..<2] // produces "ab"
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.