Как вы используете строку.substringWithRange? (или, как диапазоны работают в Swift?)
я еще не смог понять, как получить подстроку a String
в Swift:
var str = “Hello, playground”
func test(str: String) -> String {
return str.substringWithRange( /* What goes here? */ )
}
test (str)
Я не могу создать диапазон в Swift. Автозаполнение на детской площадке не очень полезно - это то, что он предлагает:
return str.substringWithRange(aRange: Range<String.Index>)
Я не нашел ничего в стандартной справочной библиотеке Swift, что помогает. Вот еще одна дикая догадка:
return str.substringWithRange(Range(0, 1))
и так:
let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)
Я видел другие ответы ( Поиск индекса символ в строке Swift), согласно которым с String
тип моста NSString
," старые " методы должны работать, но неясно, как-например, это тоже не работает (не похоже на допустимый синтаксис):
let x = str.substringWithRange(NSMakeRange(0, 3))
мысли?
30 ответов:
вы можете использовать метод substringWithRange. Он принимает начало и конец строки.Индекс.
var str = "Hello, playground" str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"
чтобы изменить начальный и конечный индексы, используйте advancedBy (n).
var str = "Hello, playground" str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"
вы также можете использовать метод NSString с NSRange, но вы должны убедиться, что вы используете NSString следующим образом:
let myNSString = str as NSString myNSString.substringWithRange(NSRange(location: 0, length: 3))
Примечание: как уже упоминалось JanX2, этот второй метод небезопасен со строками unicode.
Swift 2
простой
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:)
иsubstring(from:)
устарели вSwift 4
.String(str[..<startIndex]) // "My " String(str[startIndex...]) // "String" String(str[startIndex...endIndex]) // "Strin"
Примечание: @airspeedswift делает некоторые очень проницательно точки о компромиссах этого подхода, в частности о скрытом влиянии на производительность. Строки не являются простыми животными, и получение определенного индекса может занять O(n) времени, что означает, что цикл, который использует индекс, может быть O(n^2). Вы были предупреждены.
вам просто нужно добавить новый
subscript
функция, которая принимает диапазон и используетadvancedBy()
чтобы идти туда, где вы хочу: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"
(это определенно должно быть частью языка. Пожалуйста, обманите rdar://17158813)для удовольствия, вы также можете добавить
+
оператор на индексы: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)
(я еще не знаю, должно ли это быть частью языка или нет.)
в то время, когда я пишу, никакое расширение не идеально Swift 3 совместимость, так что вот тот, который охватывает все потребности, которые я мог бы придумать:
extension String { func substring(from: Int?, to: Int?) -> String { if let start = from { guard start < self.characters.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.characters.count { endIndex = self.index(self.startIndex, offsetBy: end + 1) } else { endIndex = self.endIndex } return 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) } }
и затем, вы можете использовать:
let string = "Hello,World!"
string.substring(from: 1, to: 7)
получает вас:ello,Wo
string.substring(to: 7)
получает вас:Hello,Wo
string.substring(from: 3)
получает вас:lo,World!
string.substring(from: 1, length: 4)
получает вас:ello
string.substring(length: 4, to: 7)
получает вас:o,Wo
Обновлено
substring(from: Int?, length: Int)
to поддержка начиная с нуля.
SWIFT 2.0
просто:
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
операции подстроки возвращают экземпляр типа подстроки вместо строки.
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)
это гораздо проще, чем любой из ответов здесь, как только вы найти правильный синтаксис.
Я хочу забрать [ и ]
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 )
результат будет " ABCDEFGHI" startIndex и endIndex также могут быть использованы в
let mySubString = myString.substringFromIndex(startIndex)
и так далее!
PS: Как указано в замечаниях, есть некоторые изменения синтаксиса в swift 2, который поставляется с xcode 7 и iOS9!
пожалуйста, посмотрите на это страница
например, чтобы найти имя (до первого пробела) в моем полном имени:
let name = "Joris Kluivers" let start = name.startIndex let end = find(name, " ") if end { let firstName = name[start..end!] } else { // no space found }
start
иend
типаString.Index
здесь и используются для созданияRange<String.Index>
и используется в методе доступа к нижнему индексу (если пробел вообще найден в исходной строке).трудно создать
String.Index
непосредственно из целочисленной позиции, используемой в открывающей записи. Это потому, что в моем имени каждый символ будет иметь одинаковый размер в байтах. Но символы с помощью специальные акценты в других языках могли бы использовать еще несколько байтов (в зависимости от используемой кодировки). Итак, на какой байт должно ссылаться целое число?можно создать новый
String.Index
из существующего с помощью методовsucc
иpred
который будет убедиться, что правильное количество байтов пропущено, чтобы добраться до следующей точки кода в кодировке. Однако в этом случае проще искать индекс первого пробела в строке, чтобы найти конечный индекс.
поскольку String является типом моста для NSString, "старые" методы должны работать, но неясно, как - например, это тоже не работает (не похоже на допустимый синтаксис):
let x = str.substringWithRange(NSMakeRange(0, 3))
для меня это очень интересная часть вашего вопроса. Строка и мост к NSString, так что большинство методы NSString do работа непосредственно на веревочке. Вы можете использовать их свободно и без раздумий. Так, например, это работает так же, как вы ожидаете:
// delete all spaces from Swift String stateName stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")
но, как это часто бывает, " у меня есть мой Моджо работает, но это просто не работает на вас.- Вы просто выбрали один из редких случаев, когда существует параллельный метод Swift с одинаковым именем, и в таком случае метод Swift затмевает метод Objective-C. Таким образом, когда вы говорите
str.substringWithRange
, Свифт думает, что вы имеете в виду стремительный метод, а не метод NSString - и тогда вы в пролете, потому что стремительный метод ожидаетRange<String.Index>
, а вы не знаете, как сделать один из них.простой выход-остановить Swift от такого затенения, явно бросив:
let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))
обратите внимание, что здесь не требуется существенной дополнительной работы. "Cast "не означает" конвертировать"; строка и эффективно NSString. Мы просто рассказываем Свифту, как посмотреть в этой переменной для целей этой одной строки кода.
действительно странная часть всего этого дело в том, что метод Swift, который вызывает все эти проблемы, недокументирован. Я понятия не имею, где он определен; он не находится в заголовке NSString, и он также не находится в заголовке Swift.
короткий ответ заключается в том, что это действительно трудно в Swift прямо сейчас. Моя догадка заключается в том, что для Apple все еще есть куча работы по методам удобства для таких вещей.
String.substringWithRange()
ждетRange<String.Index>
параметр, и насколько я могу судить, нет метода генератора дляString.Index
тип. Вы можете получитьString.Index
значения обратно изaString.startIndex
иaString.endIndex
и звонок.succ()
или.pred()
на них, но это безумие.как насчет расширения на Строковый класс, который принимает старый добрый
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)) //
обновление: Swift beta 4 решает проблемы ниже!
как это стоит [в бета-версии 3 и ранее], даже Swift-родные строки имеют некоторые проблемы с обработкой символов Юникода. Значок собаки выше работал, но следующее не работает:
let harderString = "1:1️⃣" for character in harderString { println(character) }
выход:
1 : 1 ️ ⃣
вы можете использовать эти расширения, чтобы улучшить
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) } }
использование:
let str = "Hello, playground" let substring1 = str.substringWithRange(0, end: 5) //Hello let substring2 = str.substringWithRange(7, location: 10) //playground
пример кода для получения подстроки в Swift 2.0
(i) подстрока из начального индекса
вход:-
var str = "Swift is very powerful language!" print(str) str = str.substringToIndex(str.startIndex.advancedBy(5)) print(str)
выход:-
Swift is very powerful language! Swift
(ii) подстрока из определенного индекса
вход:-
var str = "Swift is very powerful language!" print(str) str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2)) print(str)
выход:-
Swift is very powerful language! is
Я надеюсь, что это поможет вам!
простое решение с небольшим кодом.
сделать расширение, которое включает в себя основную подстроку, что почти все другие языки имеют:
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) } }
просто называть это
someString.subString(start: 0, end: 6)
обновлено для Xcode 7. Добавляет расширение строки:
использование:
var chuck: String = "Hello Chuck Norris" chuck[6...11] // => Chuck
реализация:
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) } } }
попробуйте это на детской площадке
var str:String = "Hello, playground" let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))
это даст вам "елло п"
однако, где это становится действительно интересным, так это то, что если вы сделаете последний индекс больше, чем строка в playground, он покажет любые строки, которые вы определили после str :o
Range () представляется универсальной функцией, поэтому ей необходимо знать тип, с которым она имеет дело.
вы также должны дать ему фактическую строку, интересующую вас на игровых площадках, как это кажется, чтобы держать все жала в последовательности один за другим с их именем переменной впоследствии.
Так
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))
дает "елло, детская площадка�ул.���я следующая строка�стр2�"
работает, даже если str2 определяется с помощью let
:)
Роб Нейпир уже дал удивительный ответ, используя индекс. Но я почувствовал один недостаток в том, что нет проверки на выход из связанных условий. Это может, как правило, к краху. Поэтому я изменил расширение и вот это
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)] } } }
вывод
var str2 = "Hello, World" var str3 = str2[0...5] //Hello, var str4 = str2[0..<5] //Hello var str5 = str2[0..<15] //nil
поэтому я предлагаю всегда проверять, если let
if let string = str[0...5] { //Manipulate your string safely }
In Swift3
например: переменная "Duke James Thomas", нам нужно получить"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)
взяв страницу у Роба Нейпира, я разработал эти Общие Расширения Строк, два из которых:
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)) }
использование:
"Awesome"[3...7] //"some" "Awesome".subString(3, length: 4) //"some"
вот как вы получаете диапазон от строки:
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"
ключевым моментом является то, что вы передаете диапазон значений типа String.Индекс (это то, что возвращает advance) вместо целых чисел.
причина, по которой это необходимо, заключается в том, что строки в Swift не имеют произвольного доступа (из-за переменной длины символов Юникода в основном). Вы также не можете сделать
str[1]
. Строка.Индекс предназначен для работы с их внутренней структуры.Вы можете создать расширение с индексом, хотя, что делает это для вас, так что вы можете просто передать диапазон целых чисел (см. например ответ Роба Нейпира).
Я пытался придумать что-то весть.
все индексы здесь отличные, но времена, когда мне действительно нужно что-то простое, обычно, когда я хочу считать со спины, например
string.endIndex.advancedBy(-1)
поддерживает
nil
значения, как для начального, так и для конечного индекса, гдеnil
будет означать индекс в 0 для начала,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!!
EDIT
более элегантное решение:
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!!
сначала создайте диапазон, затем подстроку. Вы можете использовать
fromIndex..<toIndex
синтаксис такой:let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string let substring = fullString.substringWithRange(range)
вот пример, чтобы получить только видео-Id .я.е (6oL687G0Iso) из всего URL в 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)
полный образец вы можете увидеть здесь
http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/ показывает, что это хорошо работает:
var str = "abcd" str = str.substringToIndex(1)
Ну, у меня была такая же проблема и решена с помощью функции "bridgeToObjectiveC ()":
var helloworld = "Hello World!" var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6)) println("\(world)") // should print World!
обратите внимание, что в Примере substringWithRange в сочетании с NSMakeRange принимают часть строки, начиная с индекса 6 (символ "W") и заканчивая индексом 6 + 6 позиций вперед (символ "!")
Ура.
вы можете использовать любой из методов подстроки в расширении строки Swift, которое я написал https://bit.ly/JString.
var string = "hello" var sub = string.substringFrom(3) // or string[3...5] println(sub)// "lo"
если у вас
NSRange
, мостNSString
работает. Например, я делал некоторые работы сUITextFieldDelegate
и я быстро хотел вычислить новое строковое значение, когда он спросил, должен ли он заменить диапазон.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) }
простой расширение на
String
:extension String { func substringToIndex(index: Int) -> String { return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))] } }
Если вы не заботитесь о производительности... это, пожалуй, самое лаконичное решение в Swift 4
extension String { subscript(range: CountableClosedRange<Int>) -> String { return enumerated().filter{.offset >= range.first! && .offset < range.last!} .reduce(""){ + String(.element)} } }
Это позволит вам сделать что-то вроде этого:
let myStr = "abcd" myStr[0..<2] // produces "ab"