如何使用string。substringwithrange ?(或者,在Swift中Ranges是如何工作的?)

我还没有弄清楚如何在Swift中获得String的子字符串:

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字符串中查找字符索引),似乎表明由于StringNSString的桥接类型,“旧”方法应该可以工作,但不清楚如何工作-例如,这也不起作用(似乎不是有效的语法):

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

想法吗?

243939 次浏览

您可以使用substringWithRange方法。它有一个开头和结尾String.Index。

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"

你也可以用NSRange使用NSString方法,但你必须确保你使用的是这样的NSString:

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

注意:正如JanX2提到的,第二个方法对于unicode字符串是不安全的。

简而言之,这在Swift中是非常困难的。我的直觉是,苹果公司仍有很多工作要做,以方便这样的事情。

String.substringWithRange()需要一个Range<String.Index>参数,据我所知,没有用于String.Index类型的生成器方法。你可以从aString.startIndexaString.endIndex中获得String.Index值,并对它们调用.succ().pred(),但这是疯狂的。

String类的一个扩展如何,它采用良好的旧Ints?

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

< em >更新: Swift beta 4解决了以下问题!< / em >

在beta 3和更早的版本中,即使是swift原生字符串在处理Unicode字符时也有一些问题。上面的狗图标起作用了,但下面的不行:

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

输出:

1
:
1
️
⃣

例如,在我的全名中查找第一个名字(直到第一个空格):

let name = "Joris Kluivers"


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


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

startend在这里是String.Index类型,用于创建Range<String.Index>并用于下标访问器(如果在原始字符串中找到空格)。

很难像开头文章中使用的那样直接从整数位置创建String.Index。这是因为在我的名字中,每个字符的字节大小都是相等的。但是在其他语言中使用特殊重音的字符可能会使用更多的字节(取决于所使用的编码)。那么这个整数应该指向哪个字节呢?

可以使用succpred方法从现有的String.Index创建一个新的String.Index,这将确保跳过正确的字节数以到达编码中的下一个代码点。然而,在这种情况下,更容易搜索字符串中第一个空格的索引来找到结束索引。

注意:@airspeedswift做了一些非常有见地的观点关于这种方法的权衡,特别是隐藏的性能影响。字符串不是简单的野兽,获得特定的索引可能需要O(n)时间,这意味着使用下标的循环可能是O(n²)。我警告过你了。

你只需要添加一个新的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"

(这绝对应该是语言的一部分。请dupe 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)

(我还不知道这个是否应该成为语言的一部分。)

关于如何解决这个问题,已经有很多很好的例子。最初的问题是关于使用substringWithRange,但正如已经指出的那样,这比仅仅做自己的扩展更难。

上述范围的解决方案是很好的。你还可以用其他十几种方法来做到这一点。下面是另一个例子,告诉你如何做到这一点:

extension String{
func sub(start: Int, length: Int) -> String {
assert(start >= 0, "Cannot extract from a negative starting index")
assert(length >= 0, "Cannot extract a negative length string")
assert(start <= countElements(self) - 1, "cannot start beyond the end")
assert(start + length <= countElements(self), "substring goes past the end of the original")
var a = self.substringFromIndex(start)
var b = a.substringToIndex(length)
return b
}
}
var s = "apple12345"
println(s.sub(6, length: 4))
// prints "2345"

http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/ 显示这工作得很好:

var str = "abcd"
str = str.substringToIndex(1)

在操场上试试这个

var str:String = "Hello, playground"


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

它会给你“嗨,p”

然而,有趣的是,如果你使最后一个索引大于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))

“你好,游乐场,我是下一个str2”

即使str2使用let定义也有效

:)

好吧,我有同样的问题,并解决了“bridgetooobjecvec()”函数:

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

请注意,在这个例子中,substringWithRange与NSMakeRange结合使用了字符串的一部分,从索引6开始(字符“W”),并在索引6 + 6位前结束(字符“!”)

欢呼。

由于String是NSString的桥接类型,因此"old"方法应该工作,但不清楚如何工作-例如,这也不起作用(似乎不是有效的语法):

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

对我来说,这是你问题中真正有趣的部分。字符串桥接到NSString,因此大多数 NSString方法直接作用于String。你可以自由地使用它们,不需要思考。例如,这正如你所期望的那样:

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

但是,就像经常发生的那样,“我的魔咒起作用了,但它对你不起作用”。你只是碰巧选择了一个罕见的存在一个同名的并行Swift方法案例,在这种情况下,Swift方法盖过了Objective-C方法。因此,当你说str.substringWithRange时,Swift认为你指的是Swift方法而不是NSString方法——然后你就完蛋了,因为Swift方法需要一个Range<String.Index>,而你不知道如何创建其中一个。

最简单的办法就是阻止霉霉这样做,明确地说:

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

注意,这里没有涉及到重大的额外工作。“Cast"并不意味着“转换”;字符串实际上是一个NSString。我们只是告诉Swift为了这一行代码的目的如何在这个变量上

整个事情中真正奇怪的部分是导致所有这些麻烦的Swift方法是没有记录的。我不知道它的定义是什么;它不在NSString头文件中也不在Swift头文件中。

借鉴Rob Napier的经验,我开发了这些常见的字符串扩展,其中两个是:

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"

一旦找到正确的语法,它比这里的任何答案都要简单得多。

我想把[和]

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 )

result will be "ABCDEFGHI" startIndex和endIndex也可以在

中使用
let mySubString = myString.substringFromIndex(startIndex)

等等!

PS:正如注释中所指出的,在xcode 7和iOS9附带的swift 2中有一些语法变化!

请看这个页面

这是你从字符串中获取范围的方法:

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中的字符串没有随机访问(因为Unicode字符的长度基本上是可变的)。你也不能做str[1]。字符串。索引的设计是为了与它们的内部结构一起工作。

你可以创建一个带有下标的扩展,这样你就可以传递一个整数范围(例如Rob Napier的答案)。

这适用于我的操场:)

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

你可以在我写的https://bit.ly/JString的Swift String扩展中使用任何子字符串方法。

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

在新的Xcode 7.0中使用

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

enter image description here

你可以使用这个扩展来改进substringWithRange

斯威夫特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)
}
}

斯威夫特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

斯威夫特2.0

简单:

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

斯威夫特3.0

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

斯威夫特4.0

子字符串操作返回Substring类型的实例,而不是String。

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)

Rob Napier已经用下标给出了一个很棒的答案。但我觉得有一个缺点,因为没有检查出约束条件。这可能会导致崩溃。所以我修改了扩展,在这里

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

所以我建议总是检查if let

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

斯威夫特2

简单的

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

斯威夫特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"

斯威夫特4

substring(to:)substring(from:)Swift 4中已弃用。

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

如何在斯威夫特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

希望对你有所帮助!

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


}

首先创建范围,然后是子字符串。你可以像这样使用fromIndex..<toIndex语法:

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

下面是一个只获取视频id .i的例子。e (6 ol687g0iso)从整个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)

String的简单扩展:

extension String {


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

我试着想出一些Pythonic的东西。

这里所有的下标都很棒,但我真正需要一些简单的东西的时候通常是当我想从后面计数时,例如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!!

编辑

一个更优雅的解决方案:

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

斯威夫特3.0

我决定有一个小乐趣与此,并产生一个扩展String。我可能没有正确地使用截断这个词在我让函数实际做的事情中。

extension String {


func truncate(from initialSpot: Int, withLengthOf endSpot: Int) -> String? {


guard endSpot > initialSpot else { return nil }
guard endSpot + initialSpot <= self.characters.count else { return nil }


let truncated = String(self.characters.dropFirst(initialSpot))
let lastIndex = truncated.index(truncated.startIndex, offsetBy: endSpot)


return truncated.substring(to: lastIndex)
}


}


let favGameOfThronesSong = "Light of the Seven"


let word = favGameOfThronesSong.truncate(from: 1, withLengthOf: 4)
// "ight"
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

完整的样本你可以看到在这里

在我写作的时候,没有一个扩展是完全兼容斯威夫特4.2的,所以这里有一个覆盖了我能想到的所有需求:

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

然后,你可以使用:

let string = "Hello,World!"

__abc0得到你:ello,Wo

__abc0得到你:Hello,Wo

__abc0得到你:lo,World!

__abc0得到你:ello

__abc0得到你:o,Wo

更新了substring(from: Int?, length: Int)以支持从0开始。

简单的解决方案,很少的代码。

做一个扩展,包括基本的子字符串,几乎所有其他语言都有:

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)

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)

斯威夫特3。X+ Xcode 8。X +测试工作简单解决方案;

使用简单;

let myString = "12.12.2017 12:34:45"
let newString = myString?[(myString?.startIndex)!..<(myString?.index((myString?.startIndex)!, offsetBy: 10))!]
print(newString)

输出= 12.12.2017

便于定制更改;

offsetBy: 10 // Change 10 to endIndex.

当你改变偏移量:10到15,20等。会割断你的绳子。

谢谢你!

如果你不关心性能……这可能是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)}
}
}

它可以让你做这样的事情:

let myStr = "abcd"
myStr[0..<2] // produces "ab"