Wie benutzt man String.substringWithRange? (oder wie funktionieren Ranges in Swift?)


266

Ich konnte noch nicht herausfinden, wie man einen Teilstring von a Stringin Swift erhält :

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

Ich kann in Swift keinen Bereich erstellen. Die automatische Vervollständigung auf dem Spielplatz ist nicht besonders hilfreich - dies schlägt vor:

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

Ich habe in der Swift Standard Reference Library nichts gefunden, was hilft. Hier war eine weitere wilde Vermutung:

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

Und das:

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

Ich habe andere Antworten gesehen ( Finden des Zeichenindex in Swift String ), die darauf hindeuten, dass die "alten" Methoden funktionieren sollten , da Stringes sich um einen Brückentyp handelt NSString, aber es ist nicht klar, wie - z. B. funktioniert dies auch nicht ( scheint keine gültige Syntax zu sein):

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

Gedanken?


Was meinst du, wenn du sagst, dass das letzte Beispiel nicht funktioniert? Verursacht es einen Fehler oder gibt es einen unerwarteten Wert zurück?
67cherries

Bitte betrügen Sie rdar: // 17158813 und fordern Sie die tiefgestellte Notation an openradar.appspot.com/radar?id=6373877630369792
Rob Napier

Antworten:


259

Sie können die Methode substringWithRange verwenden. Es dauert einen Start und ein Ende von String.Index.

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

Verwenden Sie advancedBy (n), um den Start- und Endindex zu ändern.

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

Sie können die NSString-Methode auch weiterhin mit NSRange verwenden, müssen jedoch sicherstellen, dass Sie einen NSString wie folgt verwenden:

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

Hinweis: Wie bereits in JanX2 erwähnt, ist diese zweite Methode mit Unicode-Zeichenfolgen nicht sicher.


5
Ja. Im Moment würde ich bei Bedarf weiterhin eine Brücke zu NSString schlagen. Es scheint, dass Swifts String noch unvollständig ist
Connor

14
Das ist nicht sicher! Sie gehen davon aus, dass Indizes in String und NSString austauschbar sind. Das ist nicht der Fall. Indizes in einem String beziehen sich auf Unicode-Codepunkte, während Indizes in einen NSString auf UTF-16-Codeeinheiten verweisen! Probieren Sie es mit Emoji.
JanX2

3
Bitte beachten Sie, dass Indizes in einem String NICHT mehr auf Unicode-Codepunkte verweisen. Stellen Sie sich diese als Referenz für vom Benutzer wahrgenommene Zeichen vor.
JanX2

2
Was ist hier die richtige Antwort? Aufruf advancebedeutet, dass wir den gesamten Weg durch eine möglicherweise lange Zeichenfolge durchlaufen müssen. Aber eine NSRange zu bilden und NSString explizit zu verwenden, ist gefährlich? Was ist übrig?
Matt

1
Danke, m8. Dieser Übergang zu Swift ist nach 4 Jahren nur mit Objective-C etwas chaotisch.
Felipe

162

Swift 2

Einfach

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:)und substring(from:)sind veraltet in Swift 4.

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

2
DIES. So verwirrend, dass Sie Ihren Index finden müssen, bevor Sie ihn verwenden können. Keine Ahnung, warum ich so lange gebraucht habe, aber danke für Ihren Beitrag zur menschlichen Art.
Warpzit

1
In Swift 4-Teilstring-Operationen wird anstelle von String eine Instanz vom Typ Teilstring zurückgegeben. Das Ergebnis muss zur Langzeitspeicherung in einen String konvertiert werden. let newString = String (Teilzeichenfolge)
phnmnn

43

HINWEIS: @airspeedswift macht einige sehr aufschlussreiche Punkte zu den Kompromissen dieses Ansatzes, insbesondere zu den versteckten Auswirkungen auf die Leistung. Strings sind keine einfachen Tiere, und das Erreichen eines bestimmten Index kann O (n) Zeit dauern, was bedeutet, dass eine Schleife, die einen Index verwendet, O (n ^ 2) sein kann. Du wurdest gewarnt.

Sie müssen nur eine neue subscriptFunktion hinzufügen , die einen Bereich einnimmt und verwendet advancedBy(), um zu dem gewünschten Ort zu gelangen:

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"

(Dies sollte definitiv Teil der Sprache sein. Bitte betrügen Sie: // 17158813 )

Zum Spaß können Sie +den Indizes auch einen Operator hinzufügen :

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)

(Ich weiß noch nicht, ob dieser Teil der Sprache sein soll oder nicht.)


2
Wir sollten wahrscheinlich aus Leistungsgründen so viel wie möglich mit String.Index anstelle von Ganzzahlindizes arbeiten. Jede Konvertierung von einem Ganzzahlindex in einen String.Index muss den zu suchenden String verarbeiten.
JanX2

11
@ AndrewDunn Dies ist keine vorzeitige Optimierung. Jede Konvertierung von einem Integer-Index in einen String.Index ist O (n), nicht O (1)! Bitte lesen Sie die Kommentare advance<T>(…)im SwiftNamespace.
JanX2

1
Die gesamte String-Implementierung erfolgt mit String.Index. In diesem Fall geht es nicht so sehr um Optimierung, sondern darum, alles einfach zu halten. Das Hin- und Herwechseln zwischen int und String.Index führt überall zu einem Durcheinander.
Chakrit

@chakrit Nur wenn Indizes, die Sie verwenden müssen, nicht bereits ganze Zahlen sind (anstatt String.Indexes zu sein), was häufig der Fall ist. Dann können Sie sich nur wünschen, dass all diese Methoden zur Behandlung von Zeichenfolgen mit Ints funktionieren . Und Sie sind gezwungen, es zu konvertieren, String.Indexeswas zu dem von Ihnen erwähnten Durcheinander führt.
Rasto

Der interessierte Leser sollte einen Blick auf ExSwift github.com/pNre/ExSwift
AsTeR

42

Zum Zeitpunkt des Schreibens ist keine Erweiterung perfekt mit Swift 4.2 kompatibel. Hier ist eine, die alle Anforderungen abdeckt, die mir einfallen:

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

Und dann können Sie verwenden:

let string = "Hello,World!"

string.substring(from: 1, to: 7)bringt dich: ello,Wo

string.substring(to: 7)bringt dich: Hello,Wo

string.substring(from: 3)bringt dich: lo,World!

string.substring(from: 1, length: 4)bringt dich: ello

string.substring(length: 4, to: 7)bringt dich: o,Wo

Aktualisiert substring(from: Int?, length: Int), um ab Null zu unterstützen.


Wie geht das mit Emoji und erweiterten Graphemclustern um? (Ich sollte es selbst testen, aber es ist im Moment nicht bequem.)
Suragch

2
@ Suragch Es handhabt es OK: "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)gibt uns:o😇😍😘😎📸📀💾∝ℵℶ
winterfest

Diese sehen jedoch wie normale Charaktere aus. Versuchen Sie es mit Emoji wie 👩‍👩‍👧‍👦 oder 🇨🇦🇺🇸🇲🇽
Supuhstar

31

SWIFT 2.0

einfach:

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

Teilstring-Operationen geben anstelle von String eine Instanz vom Typ Teilstring zurück.

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
Leider nicht mehr kompatibel mit Swift 3 ab Xcode 8 Beta 6
Ben Morrow

1
Funktioniert bei mir. Xcode 8, Swift 3. Nicht Beta unter Mac OS Sierra. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jose Ramirez

18

Es ist viel einfacher als jede der Antworten hier, sobald Sie die richtige Syntax gefunden haben.

Ich möchte das [und] wegnehmen

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 )

Ergebnis ist "ABCDEFGHI", in dem auch startIndex und endIndex verwendet werden können

let mySubString = myString.substringFromIndex(startIndex)

und so weiter!

PS: Wie in den Anmerkungen angegeben, gibt es in Swift 2 einige Syntaxänderungen, die mit xcode 7 und iOS9 geliefert werden!

Bitte schauen Sie sich diese Seite an


Ja, ich hatte die gleichen Probleme mit dem Debugger, der mehrmals nicht die richtige Zeichenfolge anzeigt.
user1700737

Ich habe eine Zeichenfolge wie diese / Date (147410000000) /. Wie kann ich einen Wert erhalten, anstatt den Index anzugeben? Ich muss den Wert mit rangeOfString ("(") und rangeOfString (")") abrufen. Das Ergebnis sollte 147410000000 sein. Hacke kann ich das bekommen
iPhone Guy

Das ist nicht so schwer: var str = "/ Date (147410000000) /." var range = str.rangeOfString ("(")!. endIndex .. <str.rangeOfString (")")! startIndex let myNewString = str.substringWithRange (range)
user1700737

4
seit Xcode 7 Beta 6 advance(myString.endIndex, -1)Syntax hat sich zumyString.endIndex.advancedBy(-1)
l

16

Zum Beispiel, um den Vornamen (bis zum ersten Leerzeichen) in meinem vollständigen Namen zu finden:

let name = "Joris Kluivers"

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

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

startund endsind hier vom Typ String.Indexund werden zum Erstellen eines Range<String.Index>und im Index-Accessor verwendeten verwendet (wenn in der ursprünglichen Zeichenfolge überhaupt ein Leerzeichen gefunden wird).

Es ist schwierig, eine String.Indexdirekt aus einer ganzzahligen Position zu erstellen, wie sie im Eröffnungsbeitrag verwendet wird. Dies liegt daran, dass in meinem Namen jedes Zeichen in Bytes gleich groß wäre. Zeichen mit speziellen Akzenten in anderen Sprachen könnten jedoch mehrere Bytes mehr verwendet haben (abhängig von der verwendeten Codierung). Auf welches Byte sollte sich die Ganzzahl beziehen?

Es ist möglich , eine neue erstellen String.Indexaus einer bestehenden mit den Methoden succund preddie sicherstellen, die korrekte Anzahl von Bytes an den nächsten Codepunkt in der Codierung übersprungen zu erhalten. In diesem Fall ist es jedoch einfacher, nach dem Index des ersten Leerzeichens in der Zeichenfolge zu suchen, um den Endindex zu finden.


16

Da String ein Brückentyp für NSString ist, sollten die "alten" Methoden funktionieren, aber es ist nicht klar, wie - z. B. funktioniert dies auch nicht (scheint keine gültige Syntax zu sein):

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

Für mich ist das der wirklich interessante Teil Ihrer Frage. String wird zu NSString überbrückt, so die meisten NSString Methoden tun Arbeit direkt auf einem String. Sie können sie frei und ohne nachzudenken verwenden. So funktioniert dies beispielsweise genau so, wie Sie es erwarten:

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

Aber wie so oft: "Ich habe mein Mojo zum Laufen gebracht, aber es funktioniert einfach nicht bei dir." Sie haben gerade einen der seltenen Fälle ausgewählt, in denen eine parallele Swift-Methode mit identischem Namen existiert , und in einem solchen Fall überschattet die Swift-Methode die Objective-C-Methode. Wenn Sie also sagen str.substringWithRange, Swift meint, Sie meinen eher die Swift-Methode als die NSString-Methode - und dann werden Sie abgespritzt, weil die Swift-Methode a erwartet Range<String.Index>und Sie nicht wissen, wie Sie eine davon erstellen sollen.

Der einfache Ausweg besteht darin, Swift daran zu hindern, diese zu überschatten, indem Sie explizit Folgendes tun:

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

Beachten Sie, dass hier keine wesentlichen zusätzlichen Arbeiten erforderlich sind. "Cast" bedeutet nicht "konvertieren"; Der String ist effektiv ein NSString. Wir sagen nur Swift , wie man sieht bei diesen Variablen für die Zwecke dieser einer Zeile Code.

Der wirklich seltsame Teil dieser ganzen Sache ist, dass die Swift-Methode, die all diese Probleme verursacht, nicht dokumentiert ist. Ich habe keine Ahnung, wo es definiert ist; Es befindet sich nicht im NSString-Header und auch nicht im Swift-Header.


Ich schlage jedoch vor, einen Fehler einzureichen. Apple sollte "Köder fischen oder schneiden" - entweder geben Sie uns eine Möglichkeit, einen zu konstruieren Range<String.Index>, oder wir können diese undokumentierte Methode aus dem Weg räumen .
Matt

Verdammt - das ist nützlich. Trotz der Angaben in der Dokumentation habe ich nicht verstanden, was schief gelaufen ist, bis ich dies gelesen habe. Jetzt sortiert :)
Jon M

13

In neuem Xcode 7.0 verwenden

//: 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:

Geben Sie hier die Bildbeschreibung ein


2
.advancedBy(0) ist für startIndex nicht erforderlich.
Mat0

12

Die kurze Antwort ist, dass dies in Swift momentan sehr schwierig ist. Meine Vermutung ist, dass Apple noch eine Menge Arbeit an praktischen Methoden für solche Dinge zu erledigen hat.

String.substringWithRange()erwartet einen Range<String.Index>Parameter, und soweit ich das beurteilen kann, gibt es keine Generatormethode für den String.IndexTyp. Sie können String.IndexWerte von aString.startIndexund zurückbekommen oder aString.endIndexanrufen .succ()oder .pred()auf sie, aber das ist Wahnsinn.

Wie wäre es mit einer Erweiterung der String-Klasse, die gute alte Ints nimmt?

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))   // 🐶

Update: Swift Beta 4 behebt die folgenden Probleme!

So wie es aussieht [in Beta 3 und früher], haben sogar Swift-native Strings einige Probleme mit der Handhabung von Unicode-Zeichen. Das obige Hundesymbol hat funktioniert, aber das Folgende funktioniert nicht:

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

Ausgabe:

1
:
1
️
⃣

1
Es ist seltsam, dass den Swift-Kernklassen einfach viele Grundfunktionen fehlen. Ich kann nicht glauben, dass Apple möchte, dass wir ständig auf Foundation-Klassen verweisen, um einfache Aufgaben auszuführen.
Bluedevil2k

1
Total. Denken Sie daran, dass Swift im Grunde genommen im Dunkeln entwickelt wurde und jeder eine andere Definition von "einfachen Aufgaben" hat - ich wette, wir sehen einige schnelle Iterationen zu diesen Themen.
Nate Cook

@ JanX2 - Danke, du hast vollkommen recht. Die nahtlose Überbrückung mit NSStringließ mich denken, dass ich nur Swift-native StringMethoden verwendete, da ich keine myString as NSStringAnrufe verwendete.
Nate Cook

Momentan gibt es auch einige Unicode-Fehler bei der Behandlung von Swift-nativen Zeichenfolgen: siehe meine Anmerkung am Ende.
Nate Cook

@NateCook Können Sie bitte ein Radar für dieses Problem einreichen?
JanX2

11

Sie können diese Erweiterungen verwenden, um zu verbessern 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)
    }
}

Verwendungszweck:

let str = "Hello, playground"

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

7

Beispielcode zum Abrufen von Teilzeichenfolgen in Swift 2.0

(i) Teilzeichenfolge vom Startindex

Eingang:-

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

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

Ausgabe:-

Swift is very powerful language!
Swift

(ii) Teilzeichenfolge aus einem bestimmten Index

Eingang:-

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

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

Ausgabe:-

Swift is very powerful language!
is

Ich hoffe es hilft dir!


7

Einfache Lösung mit wenig Code.

Erstellen Sie eine Erweiterung mit grundlegenden Untertiteln, die fast alle anderen Sprachen haben:

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

Nennen Sie dies einfach mit

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

1
Der Parameter 'end' bedeutet hier eigentlich Länge, daher denke ich, dass er in diesen umbenannt werden sollte.
Jovan Jovanovski

Ich finde die Verwendung von Länge ziemlich verwirrend. Es ist in der Tat das 'Ende', an dem sich der SubString befinden soll, nicht die tatsächliche Länge des SubStrings-Ergebnisses.
Oliver Dixon

6

Das funktioniert auf meinem Spielplatz :)

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

Eigentlich ist das effizienter als anzurufenadvance
Erik Aigner

2
Es funktioniert nicht auf meinem Xcode 7 (Swift 2) -Spielplatz, aber das tut es ... 'var str = "Hallo, Spielplatz"' String (Array (str.characters) [7]) // "p" String (Array ( str.characters) [7 ... 10]) // "play" String (Array (str.characters) [7 .. <10]) // "pla"
Vince O'Sullivan

6

Aktualisiert für Xcode 7. Fügt String-Erweiterung hinzu:

Verwenden:

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

Implementierung:

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

Versuchen Sie dies auf dem Spielplatz

var str:String = "Hello, playground"

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

es wird dir "ello, p" geben

Wenn Sie jedoch den letzten Index größer als die Zeichenfolge auf dem Spielplatz machen, werden alle Zeichenfolgen angezeigt, die Sie nach str: o definiert haben

Range () scheint eine generische Funktion zu sein, sodass es den Typ kennen muss, mit dem es sich handelt.

Sie müssen ihm auch die tatsächliche Zeichenfolge geben, die Sie an Spielplätzen interessiert, da sie alle Stiche nacheinander mit ihrem Variablennamen nacheinander zu halten scheint.

So

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

gibt "Hallo, Spielplatz str Ich bin der nächste String str2 "

funktioniert auch, wenn str2 mit einem let definiert ist

:) :)


Ich bin damit einverstanden, dass es im Vergleich zu Objective-C ausführlich ist, aber alles passt in eine Zeile, was ein Bonus ist.
Peter Roberts

Nun, es fehlt immer noch die eine Zeile, die den Teilstring angesichts des von Ihnen berechneten Bereichs tatsächlich druckt. Ich mag einige der anderen Lösungen, die String-Klassenerweiterungen mit Ihrer Logik erstellen, aber in einer Erweiterung. Das ist letztendlich die Lösung, mit der ich mich entschieden habe.
Roderic Campbell

Sie haben den Fehler behoben, durch den Sie über das Ende der Zeichenfolge hinausgehen können. Jetzt können Sie nur noch einen Wert bis str.endIndex
Peter Roberts

4

Rob Napier hatte bereits eine großartige Antwort mit Index gegeben. Aber ich fühlte einen Nachteil darin, da es keine Überprüfung für nicht gebundene Bedingungen gibt. Dies kann zum Absturz neigen. Also habe ich die Erweiterung modifiziert und hier ist sie

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

Ausgabe unten

var str2 = "Hello, World"

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

Also schlage ich vor, immer nach dem if let zu suchen

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

Sie haben dort einen Fehler - endIndex sollte startIndex nur von endIndex erweitert werden, nicht der Abstand zwischen den Indizes.
Aviad Ben Dov

3

In Swift3

Zum Beispiel: eine Variable "Duke James Thomas", wir müssen "James" bekommen.

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

Auf einer Seite von Rob Napier habe ich diese Common String Extensions entwickelt , von denen zwei sind:

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

Verwendungszweck:

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

Sie können Rangeanstelle von Range<String.Index>dank Typinferenz verwenden.
Dan Rosenstark

2

So erhalten Sie einen Bereich aus einer Zeichenfolge:

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"

Der entscheidende Punkt ist, dass Sie anstelle von Ganzzahlen einen Wertebereich vom Typ String.Index (dies ist, was der Fortschritt zurückgibt) übergeben.

Der Grund, warum dies notwendig ist, ist, dass Zeichenfolgen in Swift keinen wahlfreien Zugriff haben (aufgrund der variablen Länge der Unicode-Zeichen im Grunde). Das kannst du auch nichtstr[1] . String.Index arbeitet mit ihrer internen Struktur.

Sie können jedoch eine Erweiterung mit einem Index erstellen, die dies für Sie erledigt, sodass Sie nur eine Reihe von Ganzzahlen übergeben können (siehe z. B. Rob Napiers Antwort ).


2

Ich habe versucht, mir etwas Pythonisches auszudenken.

Alle Indizes hier sind großartig, aber die Zeiten, in denen ich wirklich etwas Einfaches brauche, sind normalerweise, wenn ich von hinten zählen möchte, z string.endIndex.advancedBy(-1)

Es werden nilWerte sowohl für den Start- als auch für den Endindex unterstützt, wobei nilder Index bei 0 für Start und Ende bedeuten würde string.characters.count.

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!!

BEARBEITEN

Eine elegantere Lösung:

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

Erstellen Sie zuerst den Bereich und dann den Teilstring. Sie können die folgende fromIndex..<toIndexSyntax verwenden:

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

1

Hier ist ein Beispiel, um nur die Video-ID .ie (6oL687G0Iso) schnell von der gesamten URL abzurufen

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)

Das vollständige Beispiel finden Sie hier



0

Nun, ich hatte das gleiche Problem und löste es mit der Funktion "bridgeToObjectiveC ()":

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

Bitte beachten Sie, dass im Beispiel substringWithRange in Verbindung mit NSMakeRange den Teil der Zeichenfolge übernimmt, der bei Index 6 (Zeichen "W") beginnt und bei Index 6 + 6 Positionen vor (Zeichen "!") Endet.

Prost.


Ich hasse das, aber es ist das einzige, was in Beta 4 für mich zu funktionieren scheint.
Roderic Campbell


0

Wenn Sie eine haben NSRange, NSStringfunktioniert die Überbrückung nahtlos. Zum Beispiel habe ich mit gearbeitet UITextFieldDelegateund wollte schnell den neuen Zeichenfolgenwert berechnen, als er gefragt wurde, ob er den Bereich ersetzen soll.

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

Einfache Erweiterung für String:

extension String {

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

0

Wenn Sie sich nicht für die Leistung interessieren ... ist dies wahrscheinlich die prägnanteste Lösung 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)}
    }
}

Damit können Sie Folgendes tun:

let myStr = "abcd"
myStr[0..<2] // produces "ab"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.