Je n'ai pas encore été capable de comprendre comment obtenir une sous-chaîne de String
dans Swift:
var str = “Hello, playground”
func test(str: String) -> String {
return str.substringWithRange( /* What goes here? */ )
}
test (str)
Je ne suis pas en mesure de créer une plage dans Swift. La saisie semi-automatique sur le terrain de jeu n’est pas très utile, c’est ce qu’elle suggère:
return str.substringWithRange(aRange: Range<String.Index>)
Je n'ai rien trouvé dans la bibliothèque de référence standard de Swift qui aide. Voici une autre supposition sauvage:
return str.substringWithRange(Range(0, 1))
Et ça:
let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)
J'ai vu d'autres réponses ( Trouver l'index du caractère dans Swift String ) qui semblent suggérer que, puisque String
est un type de pont pour NSString
, les "anciennes" méthodes devraient fonctionner, mais on ne sait pas comment - par exemple, ceci ne fonctionne pas non plus (ne semble pas être une syntaxe valide):
let x = str.substringWithRange(NSMakeRange(0, 3))
Pensées?
Vous pouvez utiliser la méthode substringWithRange. Il faut un début et une fin String.Index.
var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"
Pour modifier les index de début et de fin, utilisez advancedBy (n).
var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"
Vous pouvez également toujours utiliser la méthode NSString avec NSRange, mais vous devez vous assurer que vous utilisez un NSString comme ceci:
let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))
Remarque: comme JanX2 l'a mentionné, cette seconde méthode n'est pas sûre avec les chaînes unicode.
Simple
let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"
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"
substring(to:)
et substring(from:)
sont obsolètes en Swift 4
.
String(str[..<startIndex]) // "My "
String(str[startIndex...]) // "String"
String(str[startIndex...endIndex]) // "Strin"
NOTE: @airspeedswift fait quelques des points très perspicaces sur les compromis de cette approche, en particulier les impacts cachés sur les performances. Les chaînes ne sont pas de simples animaux, et atteindre un index particulier peut prendre du temps O(n), ce qui signifie qu'une boucle utilisant un indice peut être O (n ^ 2). Tu étais prévenu.
Vous devez simplement ajouter une nouvelle fonction subscript
qui prend une plage et utilise advancedBy()
pour aller où vous voulez:
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"
(Cela devrait certainement faire partie de la langue. Veuillez duper rdar: // 17158813 )
Pour le plaisir, vous pouvez également ajouter un opérateur +
sur les index:
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)
(Je ne sais pas encore si celui-ci devrait faire partie de la langue ou non.)
Au moment où j'écris, aucune extension n'est parfaitement compatible Swift 4.2. En voici donc une qui couvre tous les besoins auxquels je peux penser:
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)
}
}
Et puis, vous pouvez utiliser:
let string = "Hello,World!"
string.substring(from: 1, to: 7)
getget: Ello,Wo
string.substring(to: 7)
getget: Hello,Wo
string.substring(from: 3)
getget: lo,World!
string.substring(from: 1, length: 4)
getget vous: Ello
string.substring(length: 4, to: 7)
getget: o,Wo
Mis à jour substring(from: Int?, length: Int)
pour prendre en charge à partir de zéro.
Swift 2.0
simple:
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
Les opérations de sous-chaîne renvoient une instance du type Sous-chaîne au lieu de Chaîne.
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)
C'est beaucoup plus simple que n'importe quelle réponse, une fois que vous avez trouvé la bonne syntaxe.
Je veux enlever le [et]
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 )
le résultat sera "ABCDEFGHI" les index startIndex et endIndex peuvent également être utilisés dans
let mySubString = myString.substringFromIndex(startIndex)
etc!
PS: Comme indiqué dans les remarques, il y a quelques changements de syntaxe dans Swift 2, qui vient avec xcode 7 et iOS9!
S'il vous plaît regardez cette page
Par exemple, pour trouver le prénom (jusqu'au premier espace) dans mon nom complet:
let name = "Joris Kluivers"
let start = name.startIndex
let end = find(name, " ")
if end {
let firstName = name[start..end!]
} else {
// no space found
}
start
et end
sont de type String.Index
ici et sont utilisés pour créer un Range<String.Index>
et utilisés dans l'accesseur en indice (si un espace est trouvé dans la chaîne d'origine).
Il est difficile de créer un String.Index
directement à partir d'une position entière telle qu'utilisée dans le post d'ouverture. En effet, chaque caractère de mon nom aurait la même taille en octets. Mais les caractères utilisant des accents spéciaux dans d'autres langues auraient pu utiliser plusieurs octets supplémentaires (en fonction du codage utilisé). Alors, à quel octet le nombre entier devrait-il se référer?
Il est possible de créer un nouveau String.Index
à partir d'un existant en utilisant les méthodes succ
et pred
qui permettront de s'assurer que le nombre d'octets correct est ignoré pour atteindre le prochain point de code du codage. Cependant, dans ce cas, il est plus facile de rechercher l'index du premier espace de la chaîne pour trouver l'index de fin.
Puisque String est un type de pont pour NSString, les "anciennes" méthodes devraient fonctionner, mais il n'est pas clair comment - par exemple, cela ne fonctionne pas non plus (ne semble pas être une syntaxe valide):
let x = str.substringWithRange(NSMakeRange(0, 3))
Pour moi, c'est la partie vraiment intéressante de votre question. String est ponté vers NSString, donc la plupart méthodes NSString do travaillent directement sur une chaîne. Vous pouvez les utiliser librement et sans réfléchir. Ainsi, par exemple, cela fonctionne exactement comme vous le souhaitiez:
// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")
Mais, comme cela arrive souvent, "je travaille mon mojo mais ça ne marche pas pour toi." Vous venez de choisir l'un des rares cas où il existe un parallèle portant le même nom que la méthode Swift , et dans un cas comme celui-là, la méthode Swift masque la méthode Objective-C. Ainsi, lorsque vous dites str.substringWithRange
, Swift pense que vous voulez parler de la méthode Swift plutôt que de la méthode NSString - et ensuite vous êtes insensé, car la méthode Swift attend un Range<String.Index>
, et vous ne savez pas comment en créer un.
La solution de facilité est d’empêcher Swift de prendre une telle ombre, en exprimant explicitement:
let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))
Notez qu'aucun travail supplémentaire important n'est impliqué ici. "Cast" ne signifie pas "convertir"; the String est est effectivement une chaîne NSString. Nous disons simplement à Swift comment regarder cette variable pour les besoins de cette ligne de code.
La partie vraiment étrange de tout cela est que la méthode Swift, qui cause tout ce problème, est non documentée. Je ne sais pas où c'est défini; ce n'est pas dans l'en-tête NSString et ce n'est pas non plus dans l'en-tête Swift.
La réponse courte est que c'est vraiment difficile à Swift en ce moment. Mon impression est qu'il reste encore beaucoup de travail pour Apple à faire sur les méthodes pratiques pour des choses comme celle-ci.
String.substringWithRange()
attend un paramètre Range<String.Index>
et, autant que je sache, il n'existe pas de méthode de génération pour le type String.Index
. Vous pouvez récupérer les valeurs String.Index
à partir de aString.startIndex
et aString.endIndex
et appeler .succ()
ou .pred()
, mais c’est de la folie.
Que diriez-vous d’une extension de la classe String qui utilise de bons vieux Int
s?
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)) // ????
Mise à jour: Swift beta 4 résout les problèmes ci-dessous!
En l'état actuel des versions 3 et antérieures, même les chaînes natives de Swift ont quelques problèmes avec la gestion des caractères Unicode. L'icône de chien ci-dessus a fonctionné, mais ce qui suit ne fonctionne pas:
let harderString = "1:1️⃣"
for character in harderString {
println(character)
}
Sortie:
1
:
1
️
⃣
Vous pouvez utiliser cette extension pour améliorer 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)
}
}
Usage:
let str = "Hello, playground"
let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground
Exemple de code expliquant comment obtenir une sous-chaîne dans Swift 2.0
(i) Sous-chaîne à partir de l'index de départ
Contribution:-
var str = "Swift is very powerful language!"
print(str)
str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)
Sortie:-
Swift is very powerful language!
Swift
(ii) Sous-chaîne d'un index particulier
Contribution:-
var str = "Swift is very powerful language!"
print(str)
str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)
Sortie:-
Swift is very powerful language!
is
J'espère que cela vous aidera!
Solution facile avec peu de code.
Créez une extension qui inclut des sous-chaînes de base que presque toutes les autres langues ont:
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)
}
}
Il suffit d'appeler cela avec
someString.subString(start: 0, end: 6)
Cela fonctionne dans mon terrain de jeu :)
String(seq: Array(str)[2...4])
Mise à jour pour Xcode 7. Ajout de l'extension de chaîne:
Utilisation:
var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck
La mise en oeuvre:
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)
}
}
}
Rob Napier avait déjà donné une réponse géniale en utilisant l'indice. Mais j’ai ressenti un inconvénient car il n’ya pas de vérification des conditions hors limites. Cela peut avoir tendance à tomber en panne. J'ai donc modifié l'extension et la voici
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)]
}
}
}
Sortie ci-dessous
var str2 = "Hello, World"
var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil
Je suggère donc de toujours vérifier si le laisse
if let string = str[0...5]
{
//Manipulate your string safely
}
essayez ceci dans la cour de récréation
var str:String = "Hello, playground"
let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))
cela vous donnera "Ello, p"
Cependant, là où cela devient vraiment intéressant, c'est que si vous faites le dernier index plus grand que la chaîne dans un terrain de jeu, il affichera toutes les chaînes que vous avez définies après str: o
Range () semble être une fonction générique, de sorte qu'il a besoin de connaître le type auquel elle fait face.
Vous devez également lui indiquer la chaîne qui vous intéresse dans les terrains de jeu, car elle semble contenir toutes les piqûres dans une séquence les unes après les autres avec leur nom de variable par la suite.
Alors
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))
donne "Ello, playground str Je suis la prochaine chaîne str2 "
fonctionne même si str2 est défini avec un let
:)
Dans Swift3
Par exemple: une variable "Duke James Thomas", nous devons obtenir "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)
En prenant une page de Rob Napier, j'ai développé ces Common String Extensions , dont deux sont:
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))
}
Usage:
"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"
Voici comment obtenir une plage à partir d'une chaîne:
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"
Le point clé est que vous transmettez une plage de valeurs de type String.Index (c'est ce que advance renvoie) au lieu d'entiers.
La raison pour laquelle cela est nécessaire est que les chaînes dans Swift n’ont pas d’accès aléatoire (essentiellement à cause de la longueur variable des caractères Unicode). Vous ne pouvez pas non plus faire str[1]
. String.Index est conçu pour fonctionner avec leur structure interne.
Vous pouvez cependant créer une extension avec un indice qui le fait pour vous. Vous pouvez donc simplement passer une plage d’entiers (voir par exemple Réponse de Rob Napier ).
voici un exemple pour obtenir video-Id uniquement .i.e (6oL687G0Iso) à partir de l'URL complète dans Swift
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)
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)
Échantillon complet, vous pouvez voir ici
Commencez par créer la plage, puis la sous-chaîne. Vous pouvez utiliser la syntaxe fromIndex..<toIndex
comme suit:
let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)
http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-Swift/ montre que cela fonctionne bien
var str = "abcd"
str = str.substringToIndex(1)
Si vous avez une NSRange
, le pontage à NSString
fonctionne de manière transparente. Par exemple, je travaillais avec UITextFieldDelegate
et je voulais rapidement calculer la nouvelle valeur de chaîne quand il me demandait si elle devait remplacer la plage.
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)
}
Si vous ne vous souciez pas de la performance ... c'est probablement la solution la plus concise de 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)}
}
}
Cela vous permet de faire quelque chose comme ceci:
let myStr = "abcd"
myStr[0..<2] // produces "ab"
Vous pouvez utiliser n’importe laquelle des méthodes de sous-chaîne dans une extension Swift String que j’ai écrite https://bit.ly/JString .
var string = "hello"
var sub = string.substringFrom(3) // or string[3...5]
println(sub)// "lo"
Simple extension pour String
:
extension String {
func substringToIndex(index: Int) -> String {
return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
}
}
Eh bien, j'ai eu le même problème et résolu avec la fonction "bridgeToObjectiveC ()":
var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!
Veuillez noter que dans l'exemple, substringWithRange, en association avec NSMakeRange, fait partie de la chaîne commençant à l'index 6 (caractère "W") et se terminant à l'index 6 + 6 positions (caractère "!")
À votre santé.