在Swift中获取字符串的第n个字符

我怎样才能得到字符串的第n个字符?我尝试了括号([])访问器,没有运气。

var string = "Hello, world!"


var firstChar = string[0] // Throws error

错误:'下标'是不可用的:不能下标String与Int,请参阅文档注释讨论

406728 次浏览

swift字符串类不提供在特定索引处获取字符的能力,因为它本身支持UTF字符。UTF字符在内存中的可变长度使得直接跳转到字符是不可能的。这意味着每次都必须手动遍历字符串。

您可以扩展String以提供一个方法,该方法将遍历字符,直到您需要的索引

extension String {
func characterAtIndex(index: Int) -> Character? {
var cur = 0
for char in self {
if cur == index {
return char
}
cur++
}
return nil
}
}


myString.characterAtIndex(0)!

Swift的String类型没有提供characterAtIndex方法,因为Unicode字符串有多种编码方式。你要用UTF8, UTF16,还是别的?

你可以通过检索String.utf8String.utf16属性来访问CodeUnit集合。你也可以通过检索String.unicodeScalars属性来访问UnicodeScalar集合。

根据NSString实现的精神,我将返回一个unichar类型。

extension String
{
func characterAtIndex(index:Int) -> unichar
{
return self.utf16[index]
}


// Allows us to use String[index] notation
subscript(index:Int) -> unichar
{
return characterAtIndex(index)
}
}


let text = "Hello Swift!"
let firstChar = text[0]

注意:请参阅Leo Dabus的回答为Swift 4和Swift 5的正确实现。

Swift 4或更高版本

Substring类型是在Swift 4中引入的,用于生成子字符串 通过与原始字符串共享存储,更快更有效,所以这是下标函数应该返回的

试试在这里

extension StringProtocol {
subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
subscript(range: Range<Int>) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..<index(startIndex, offsetBy: range.count)]
}
subscript(range: ClosedRange<Int>) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..<index(startIndex, offsetBy: range.count)]
}
subscript(range: PartialRangeFrom<Int>) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
subscript(range: PartialRangeThrough<Int>) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
subscript(range: PartialRangeUpTo<Int>) -> SubSequence { self[..<index(startIndex, offsetBy: range.upperBound)] }
}
要将Substring转换为String,您可以简单地 做String(string[0..2]),但你应该只做如果 您计划保留子字符串。否则,就更多了 有效地保持Substring.

. 如果有人能想出一个合并的好方法就太好了 这两个扩展为一个。我尝试扩展StringProtocol 没有成功,因为index方法不存在。注意:这个答案已经被编辑过了,它被正确地实现了,现在也适用于子字符串。只要确保使用一个有效的范围,以避免在对StringProtocol类型下标时崩溃。对于下标的范围不会在超出范围的值时崩溃,可以使用实现


为什么这不是内置的?

错误信息显示"请参阅文档注释以供讨论"。Apple在UnavailableStringAPIs.swift文件中提供了以下解释:

对整数字符串下标不可用。

“字符串中的ith字符”的概念具有 不同的图书馆和系统有不同的解释 组件。要选择正确的解释 根据用例和涉及的api,因此String 不能下标为整数

Swift提供了几种不同的方式来访问角色

  • String.utf8是UTF-8代码单元的集合 字符串。在将字符串转换为UTF-8时使用此API。 大多数POSIX api以UTF-8编码单元处理字符串。

  • String.utf16是一个UTF-16代码单元的集合 字符串。大多数Cocoa和Cocoa接触api处理字符串 UTF-16编码单元条款。例如,的实例 NSRangeNSAttributedStringNSRegularExpression存储子字符串偏移量和长度 UTF-16编码单元。

  • String.unicodeScalars是Unicode标量的集合。 在执行低级操作时使用此API 字符数据。

  • String.characters是扩展字素的集合 集群,这是用户感知的近似值 李字符。< / p > < / >

注意,当处理包含人类可读文本的字符串时, 应尽量避免逐字处理 可能的。使用高级语言环境敏感的Unicode算法,例如, String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString()等。< / p >

我刚想出了一个巧妙的变通办法

var firstChar = Array(string)[0]

不使用整数进行索引,只使用String.Index。主要是线性复杂度。你也可以从String.Index中创建范围并使用它们获取子字符串。

斯威夫特3.0

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.index(before: someString.endIndex)]
let charAtIndex = someString[someString.index(someString.startIndex, offsetBy: 10)]


let range = someString.startIndex..<someString.index(someString.startIndex, offsetBy: 10)
let substring = someString[range]

快2.倍

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.endIndex.predecessor()]
let charAtIndex = someString[someString.startIndex.advanceBy(10)]


let range = someString.startIndex..<someString.startIndex.advanceBy(10)
let subtring = someString[range]

请注意,不能使用从一个字符串到另一个字符串创建的索引(或范围)

let index10 = someString.startIndex.advanceBy(10)


//will compile
//sometimes it will work but sometimes it will crash or result in undefined behaviour
let charFromAnotherString = anotherString[index10]

为了提供主题并显示快速下标的可能性,这里有一个基于“substring-toolbox”下标的小字符串

这些方法是安全的,并且不会遍历字符串索引

extension String {
// string[i] -> one string char
subscript(pos: Int) -> String { return String(Array(self)[min(self.length-1,max(0,pos))]) }


// string[pos,len] -> substring from pos for len chars on the left
subscript(pos: Int, len: Int) -> String { return self[pos, len, .pos_len, .left2right] }


// string[pos, len, .right2left] -> substring from pos for len chars on the right
subscript(pos: Int, len: Int, way: Way) -> String { return self[pos, len, .pos_len, way] }


// string[range] -> substring form start pos on the left to end pos on the right
subscript(range: Range<Int>) -> String { return self[range.startIndex, range.endIndex, .start_end, .left2right] }


// string[range, .right2left] -> substring start pos on the right to end pos on the left
subscript(range: Range<Int>, way: Way) -> String { return self[range.startIndex, range.endIndex, .start_end, way] }


var length: Int { return countElements(self) }
enum Mode { case pos_len, start_end }
enum Way { case left2right, right2left }
subscript(var val1: Int, var val2: Int, mode: Mode, way: Way) -> String {
if mode == .start_end {
if val1 > val2 { let val=val1 ; val1=val2 ; val2=val }
val2 = val2-val1
}
if way == .left2right {
val1 = min(self.length-1, max(0,val1))
val2 = min(self.length-val1, max(1,val2))
} else {
let val1_ = val1
val1 = min(self.length-1, max(0, self.length-val1_-val2 ))
val2 = max(1, (self.length-1-val1_)-(val1-1) )
}
return self.bridgeToObjectiveC().substringWithRange(NSMakeRange(val1, val2))


//-- Alternative code without bridge --
//var range: Range<Int> = pos...(pos+len-1)
//var start = advance(startIndex, range.startIndex)
//var end = advance(startIndex, range.endIndex)
//return self.substringWithRange(Range(start: start, end: end))
}
}




println("0123456789"[3]) // return "3"


println("0123456789"[3,2]) // return "34"


println("0123456789"[3,2,.right2left]) // return "56"


println("0123456789"[5,10,.pos_len,.left2right]) // return "56789"


println("0123456789"[8,120,.pos_len,.right2left]) // return "01"


println("0123456789"[120,120,.pos_len,.left2right]) // return "9"


println("0123456789"[0...4]) // return "01234"


println("0123456789"[0..4]) // return "0123"


println("0123456789"[0...4,.right2left]) // return "56789"


println("0123456789"[4...0,.right2left]) // return "678" << because ??? range can wear endIndex at 0 ???

我的解决方案是在一行中,假设cadena是字符串,4是你想要的第n个位置:

let character = cadena[advance(cadena.startIndex, 4)]

简单的…我想Swift在未来的版本中会包含更多关于子字符串的内容。

斯威夫特5.2

let str = "abcdef"
str[1 ..< 3] // returns "bc"
str[5] // returns "f"
str[80] // returns ""
str.substring(fromIndex: 3) // returns "def"
str.substring(toIndex: str.length - 2) // returns "abcd"

你需要将这个String扩展添加到你的项目中(它已经完全测试过了):

extension String {


var length: Int {
return count
}


subscript (i: Int) -> String {
return self[i ..< i + 1]
}


func substring(fromIndex: Int) -> String {
return self[min(fromIndex, length) ..< length]
}


func substring(toIndex: Int) -> String {
return self[0 ..< max(0, toIndex)]
}


subscript (r: Range<Int>) -> String {
let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
upper: min(length, max(0, r.upperBound))))
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(start, offsetBy: range.upperBound - range.lowerBound)
return String(self[start ..< end])
}
}

即使Swift总是有开箱即用的解决方案来解决这个问题(没有字符串扩展,我在下面提供),我仍然会使用扩展强烈推荐。为什么?因为它为我从早期版本的Swift中节省了数十个小时的痛苦迁移,在早期版本中,String的语法几乎每次发布都要更改,但我所需要做的只是更新扩展的实现,而不是重构整个项目。做出你的选择。

let str = "Hello, world!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // returns Character 'o'


let endIndex = str.index(str.endIndex, offsetBy:-2)
str[index ..< endIndex] // returns String "o, worl"


String(str.suffix(from: index)) // returns String "o, world!"
String(str.prefix(upTo: index)) // returns String "Hell"

看第一个字母:

first(str) // retrieve first letter
< p >更多: http://sketchytech.blogspot.com/2014/08/swift-pure-swift-method-for-returning.html < / p >

如果你看到Cannot subscript a value of type 'String'...,使用这个扩展:

斯威夫特3

extension String {
subscript (i: Int) -> Character {
return self[self.characters.index(self.startIndex, offsetBy: i)]
}


subscript (i: Int) -> String {
return String(self[i] as Character)
}


subscript (r: Range<Int>) -> String {
let start = index(startIndex, offsetBy: r.lowerBound)
let end = index(startIndex, offsetBy: r.upperBound)
return self[start..<end]
}


subscript (r: ClosedRange<Int>) -> String {
let start = index(startIndex, offsetBy: r.lowerBound)
let end = index(startIndex, offsetBy: r.upperBound)
return self[start...end]
}
}

斯威夫特2.3

extension String {
subscript(integerIndex: Int) -> Character {
let index = advance(startIndex, integerIndex)
return self[index]
}


subscript(integerRange: Range<Int>) -> String {
let start = advance(startIndex, integerRange.startIndex)
let end = advance(startIndex, integerRange.endIndex)
let range = start..<end
return self[range]
}
}

来源:http://oleb.net/blog/2014/07/swift-strings/

我也有同样的问题。简单地这样做:

var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)

Swift 2.2解决方案:

下面的扩展在Xcode 7中工作,这是解决方案和Swift 2.0语法转换的组合。

extension String {
subscript(integerIndex: Int) -> Character {
let index = startIndex.advancedBy(integerIndex)
return self[index]
}


subscript(integerRange: Range<Int>) -> String {
let start = startIndex.advancedBy(integerRange.startIndex)
let end = startIndex.advancedBy(integerRange.endIndex)
let range = start..<end
return self[range]
}
}

swift 2.0子字符串更新

public extension String {
public subscript (i: Int) -> String {
return self.substringWithRange(self.startIndex..<self.startIndex.advancedBy(i + 1))
}


public subscript (r: Range<Int>) -> String {
get {
return self.substringWithRange(self.startIndex.advancedBy(r.startIndex)..<self.startIndex.advancedBy(r.endIndex))
}
}


}

Swift 2.0的Xcode 7通用种子

var text = "Hello, world!"


let firstChar = text[text.startIndex.advancedBy(0)] // "H"

对于第n个字符,将0替换为n-1。

编辑:Swift 3.0

text[text.index(text.startIndex, offsetBy: 0)]
< p >
注意:有更简单的方法来获取字符串

中的某些字符

例如let firstChar = text.characters.first

顺便说一句,有几个函数可以直接应用于String的字符链表示,像这样:

var string = "Hello, playground"
let firstCharacter = string.characters.first // returns "H"
let lastCharacter = string.characters.last // returns "d"

结果类型为Character,但可以将其转换为String。

或:

let reversedString = String(string.characters.reverse())
// returns "dnuorgyalp ,olleH"

: -)

一个类似蟒蛇的解决方案,允许你使用负下标,

var str = "Hello world!"
str[-1]        // "!"

可能是:

extension String {
subscript (var index:Int)->Character{
get {
let n = distance(self.startIndex, self.endIndex)
index %= n
if index < 0 { index += n }
return self[advance(startIndex, index)]
}
}
}

顺便说一下,将整个Python的切片符号转置可能是值得的

斯威夫特4

let str = "My String"

索引处的字符串

let index = str.index(str.startIndex, offsetBy: 3)
String(str[index])    // "S"

子字符串

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)
String(str[startIndex...endIndex])     // "Strin"

前n个字符

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[..<startIndex])    // "My "

最后n个字符

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[startIndex...])    // "String"

Swift 2和3

str = "My String"

**字符串索引**

斯威夫特2

let charAtIndex = String(str[str.startIndex.advancedBy(3)])  // charAtIndex = "S"

斯威夫特3

str[str.index(str.startIndex, offsetBy: 3)]

SubString fromIndex toIndex

斯威夫特2

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

斯威夫特3

str[str.index(str.startIndex, offsetBy: 3)...str.index(str.startIndex, offsetBy: 7)]

前n个字符

let first2Chars = String(str.characters.prefix(2)) // first2Chars = "My"

最后n个字符

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"

你可以使用SwiftString (https://github.com/amayne/SwiftString)来做到这一点。

"Hello, world!"[0] // H
"Hello, world!"[0...4] // Hello

免责声明:我写了这个扩展

你也可以像这样将字符串转换为字符数组:

let text = "My Text"
let index = 2
let charSequence = text.unicodeScalars.map{ Character($0) }
let char = charSequence[index]

这是在常数时间内在指定索引处获取char的方法。

下面的示例不是在常数时间内运行,而是需要线性时间。所以如果你有很多搜索字符串索引使用上述方法。

let char = text[text.startIndex.advancedBy(index)]

我认为获取第一个字符的快速答案可能是:

let firstCharacter = aString[aString.startIndex]

它的优雅和性能比:

let firstCharacter = Array(aString.characters).first

但. .如果你想操纵和做更多的操作与字符串,你可以考虑创建一个扩展..这是一个扩展与这种方法,它非常类似于已经在这里张贴:

extension String {
var length : Int {
return self.characters.count
}


subscript(integerIndex: Int) -> Character {
let index = startIndex.advancedBy(integerIndex)
return self[index]
}


subscript(integerRange: Range<Int>) -> String {
let start = startIndex.advancedBy(integerRange.startIndex)
let end = startIndex.advancedBy(integerRange.endIndex)
let range = start..<end
return self[range]
}

但这是个糟糕的主意!!

下面的扩展是非常低效的。每次使用整数访问字符串时,都会运行一个O(n)函数来提高其起始索引。在另一个线性循环中运行一个线性循环意味着这个for循环意外地是O(n2)——随着字符串长度的增加,这个循环所花费的时间呈二次方增加。

而不是这样做,你可以使用字符的字符串集合。

Xcode 11•Swift 5.1

你可以扩展StringProtocol使下标对子字符串也可用:

extension StringProtocol {
subscript(_ offset: Int)                     -> Element     { self[index(startIndex, offsetBy: offset)] }
subscript(_ range: Range<Int>)               -> SubSequence { prefix(range.lowerBound+range.count).suffix(range.count) }
subscript(_ range: ClosedRange<Int>)         -> SubSequence { prefix(range.lowerBound+range.count).suffix(range.count) }
subscript(_ range: PartialRangeThrough<Int>) -> SubSequence { prefix(range.upperBound.advanced(by: 1)) }
subscript(_ range: PartialRangeUpTo<Int>)    -> SubSequence { prefix(range.upperBound) }
subscript(_ range: PartialRangeFrom<Int>)    -> SubSequence { suffix(Swift.max(0, count-range.lowerBound)) }
}

extension LosslessStringConvertible {
var string: String { .init(self) }
}

extension BidirectionalCollection {
subscript(safe offset: Int) -> Element? {
guard !isEmpty, let i = index(startIndex, offsetBy: offset, limitedBy: index(before: endIndex)) else { return nil }
return self[i]
}
}

测试

let test = "Hello USA 🇺🇸!!! Hello Brazil 🇧🇷!!!"
test[safe: 10]   // "🇺🇸"
test[11]   // "!"
test[10...]   // "🇺🇸!!! Hello Brazil 🇧🇷!!!"
test[10..<12]   // "🇺🇸!"
test[10...12]   // "🇺🇸!!"
test[...10]   // "Hello USA 🇺🇸"
test[..<10]   // "Hello USA "
test.first   // "H"
test.last    // "!"


// Subscripting the Substring
test[...][...3]  // "Hell"


// Note that they all return a Substring of the original String.
// To create a new String from a substring
test[10...].string  // "🇺🇸!!! Hello Brazil 🇧🇷!!!"

斯威夫特3

extension String {


public func charAt(_ i: Int) -> Character {
return self[self.characters.index(self.startIndex, offsetBy: i)]
}


public subscript (i: Int) -> String {
return String(self.charAt(i) as Character)
}


public subscript (r: Range<Int>) -> String {
return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
}


public subscript (r: CountableClosedRange<Int>) -> String {
return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
}


}

使用

let str = "Hello World"
let sub = str[0...4]

有用的编程技巧和技巧(由我写的)

我想指出的是,如果你有一个很大的字符串,并且需要从中随机访问许多字符,你可能想要支付额外的内存成本,并将字符串转换为一个数组以获得更好的性能:

// Pay up front for O(N) memory
let chars = Array(veryLargeString.characters)


for i in 0...veryLargeNumber {
// Benefit from O(1) access
print(chars[i])
}

在Swift 3中,没有对String类的扩展,就像我能做的那样简单!

let myString = "abcedfg"
let characterLocationIndex = myString.index(myString.startIndex, offsetBy: 3)
let myCharacter = myString[characterLocationIndex]

本例中的myCharacter为“3”。

使用字符可以完成这项工作。您可以快速地将字符串转换为字符数组,可以由CharacterView方法操作。

例子:

let myString = "Hello World!"
let myChars  = myString.characters

(完整的CharacterView文档)

(在Swift 3中测试)

Swift3

可以使用下标语法访问特定String索引处的Character。

let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a

访问https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

或者我们可以在斯威夫特4中做一个字符串扩展

extension String {
func getCharAtIndex(_ index: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: index)]
}
}

用法:

let foo = "ABC123"
foo.getCharAtIndex(2) //C

允许负指数

在使用下标扩展时,不总是必须编写string[string.length - 1]来获取最后一个字符总是有用的。这个(斯威夫特3)扩展允许负索引,范围和CountableClosedRange。

extension String {
var count: Int { return self.characters.count }


subscript (i: Int) -> Character {
// wraps out of bounds indices
let j = i % self.count
// wraps negative indices
let x = j < 0 ? j + self.count : j


// quick exit for first
guard x != 0 else {
return self.characters.first!
}


// quick exit for last
guard x != count - 1 else {
return self.characters.last!
}


return self[self.index(self.startIndex, offsetBy: x)]
}


subscript (r: Range<Int>) -> String {
let lb = r.lowerBound
let ub = r.upperBound


// quick exit for one character
guard lb != ub else { return String(self[lb]) }


return self[self.index(self.startIndex, offsetBy: lb)..<self.index(self.startIndex, offsetBy: ub)]
}


subscript (r: CountableClosedRange<Int>) -> String {
return self[r.lowerBound..<r.upperBound + 1]
}
}

如何使用:

var text = "Hello World"


text[-1]    // d
text[2]     // l
text[12]    // e
text[0...4] // Hello
text[0..<4] // Hell

对于更彻底的程序员:在这个扩展中包含针对空字符串的guard

subscript (i: Int) -> Character {
guard self.count != 0 else { return '' }
...
}


subscript (r: Range<Int>) -> String {
guard self.count != 0 else { return "" }
...
}

这是一个你可以使用的扩展,与Swift 3.1一起工作。单个索引将返回Character,这在索引String时似乎很直观,而Range将返回String

extension String {
subscript (i: Int) -> Character {
return Array(self.characters)[i]
}
    

subscript (r: CountableClosedRange<Int>) -> String {
return String(Array(self.characters)[r])
}
    

subscript (r: CountableRange<Int>) -> String {
return self[r.lowerBound...r.upperBound-1]
}
}

扩展的一些例子:

let string = "Hello"


let c1 = string[1]  // Character "e"
let c2 = string[-1] // fatal error: Index out of range


let r1 = string[1..<4] // String "ell"
let r2 = string[1...4] // String "ello"
let r3 = string[1...5] // fatal error: Array index is out of range


n.b.如果需要,你可以在上面的扩展中添加一个额外的方法来返回一个带有单个字符的String:

subscript (i: Int) -> String {
return String(self[i])
}

注意,在索引字符串时,你必须显式地指定你想要的类型:

let c: Character = string[3] // Character "l"
let s: String = string[0]    // String "H"

斯威夫特3:另一个解决方案(在操场测试)

extension String {
func substr(_ start:Int, length:Int=0) -> String? {
guard start > -1 else {
return nil
}


let count = self.characters.count - 1


guard start <= count else {
return nil
}


let startOffset = max(0, start)
let endOffset = length > 0 ? min(count, startOffset + length - 1) : count


return self[self.index(self.startIndex, offsetBy: startOffset)...self.index(self.startIndex, offsetBy: endOffset)]
}
}

用法:

let txt = "12345"


txt.substr(-1) //nil
txt.substr(0) //"12345"
txt.substr(0, length: 0) //"12345"
txt.substr(1) //"2345"
txt.substr(2) //"345"
txt.substr(3) //"45"
txt.substr(4) //"5"
txt.substr(6) //nil
txt.substr(0, length: 1) //"1"
txt.substr(1, length: 1) //"2"
txt.substr(2, length: 1) //"3"
txt.substr(3, length: 1) //"4"
txt.substr(3, length: 2) //"45"
txt.substr(3, length: 3) //"45"
txt.substr(4, length: 1) //"5"
txt.substr(4, length: 2) //"5"
txt.substr(5, length: 1) //nil
txt.substr(5, length: -1) //nil
txt.substr(-1, length: -1) //nil

斯威夫特3:

extension String {
func substring(fromPosition: UInt, toPosition: UInt) -> String? {
guard fromPosition <= toPosition else {
return nil
}


guard toPosition < UInt(characters.count) else {
return nil
}


let start = index(startIndex, offsetBy: String.IndexDistance(fromPosition))
let end   = index(startIndex, offsetBy: String.IndexDistance(toPosition) + 1)
let range = start..<end


return substring(with: range)
}
}


"ffaabbcc".substring(fromPosition: 2, toPosition: 5) // return "aabb"

还有另一种选择,在字符串的宣言中解释

extension String : BidirectionalCollection {
subscript(i: Index) -> Character { return characters[i] }
}

Swift 4.2或更高版本

使用Stringindices属性进行范围和部分范围下标

作为@LeoDabus回答得好的变体,我们可以为DefaultIndices添加一个额外的扩展,目的是允许我们在为后者实现自定义下标(通过Int专用范围和部分范围)时使用Stringindices属性。

extension DefaultIndices {
subscript(at: Int) -> Elements.Index { index(startIndex, offsetBy: at) }
}


// Moving the index(_:offsetBy:) to an extension yields slightly
// briefer implementations for these String extensions.
extension String {
subscript(range: Range<Int>) -> SubSequence {
let start = indices[range.lowerBound]
return self[start..<indices[start...][range.count]]
}
subscript(range: ClosedRange<Int>) -> SubSequence {
let start = indices[range.lowerBound]
return self[start...indices[start...][range.count]]
}
subscript(range: PartialRangeFrom<Int>) -> SubSequence {
self[indices[range.lowerBound]...]
}
subscript(range: PartialRangeThrough<Int>) -> SubSequence {
self[...indices[range.upperBound]]
}
subscript(range: PartialRangeUpTo<Int>) -> SubSequence {
self[..<indices[range.upperBound]]
}
}


let str = "foo bar baz bax"
print(str[4..<6]) // "ba"
print(str[4...6]) // "bar"
print(str[4...])  // "bar baz bax"
print(str[...6])  // "foo bar"
print(str[..<6])  // "foo ba"

感谢@LeoDabus为我指明了使用indices属性作为String下标的(其他)替代方案的方向!

斯威夫特4

String(Array(stringToIndex)[index])

这可能是一次性解决这个问题的最好方法。您可能希望首先将String转换为数组,然后再将结果转换为String。否则,将返回字符而不是字符串。

示例String(Array("HelloThere")[1])将返回"e"作为字符串。

(Array("HelloThere")[1]将返回“e”作为字符。

Swift不允许字符串像数组一样被索引,但这就完成了工作,用蛮力的方式。

我的解决方法很简单:

斯威夫特4.1:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]

斯威夫特5.1:

let firstCharacter = myString[String.Index.init(utf16Offset: index, in: myString)]

在项目中包含此扩展

  extension String{
func trim() -> String
{
return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
}


var length: Int {
return self.count
}


subscript (i: Int) -> String {
return self[i ..< i + 1]
}


func substring(fromIndex: Int) -> String {
return self[min(fromIndex, length) ..< length]
}


func substring(toIndex: Int) -> String {
return self[0 ..< max(0, toIndex)]
}


subscript (r: Range<Int>) -> String {
let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
upper: min(length, max(0, r.upperBound))))
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(start, offsetBy: range.upperBound - range.lowerBound)
return String(self[start ..< end])
}


func substring(fromIndex: Int, toIndex:Int)->String{
let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
let endIndex = self.index(startIndex, offsetBy: toIndex-fromIndex)


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

然后像这样使用函数

let str = "Sample-String"


let substring = str.substring(fromIndex: 0, toIndex: 0) //returns S
let sampleSubstr = str.substring(fromIndex: 0, toIndex: 5) //returns Sample

得到,设置下标(字符串&- Swift 4.2

Swift 4.2, Xcode 10

我的答案基于@alecarlson的答案。 唯一的区别是你可以返回__ABC0或String(在某些情况下,单个Character)。你也可以__ABC3和set下标。 最后,我的答案比@alecarlson的答案更麻烦,也更长,因此,我建议你把它放在源文件中


扩展:

public extension String {
public subscript (i: Int) -> Character {
get {
return self[index(startIndex, offsetBy: i)]
}
set (c) {
let n = index(startIndex, offsetBy: i)
replaceSubrange(n...n, with: "\(c)")
}
}
public subscript (bounds: CountableRange<Int>) -> Substring {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start ..< end]
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ..< end, with: s)
}
}
public subscript (bounds: CountableClosedRange<Int>) -> Substring {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start ... end]
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ... end, with: s)
}
        

}
public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
return self[start ... end]
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
replaceSubrange(start ... end, with: s)
}
}
public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[startIndex ... end]
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ... end, with: s)
}
}
public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[startIndex ..< end]
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ..< end, with: s)
}
}
    

public subscript (i: Int) -> String {
get {
return "\(self[index(startIndex, offsetBy: i)])"
}
set (c) {
let n = index(startIndex, offsetBy: i)
self.replaceSubrange(n...n, with: "\(c)")
}
}
public subscript (bounds: CountableRange<Int>) -> String {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[start ..< end])"
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ..< end, with: s)
}
}
public subscript (bounds: CountableClosedRange<Int>) -> String {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[start ... end])"
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ... end, with: s)
}
        

}
public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
return "\(self[start ... end])"
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
replaceSubrange(start ... end, with: s)
}
}
public subscript (bounds: PartialRangeThrough<Int>) -> String {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[startIndex ... end])"
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ... end, with: s)
}
}
public subscript (bounds: PartialRangeUpTo<Int>) -> String {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[startIndex ..< end])"
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ..< end, with: s)
}
}
    

public subscript (i: Int) -> Substring {
get {
return Substring("\(self[index(startIndex, offsetBy: i)])")
}
set (c) {
let n = index(startIndex, offsetBy: i)
replaceSubrange(n...n, with: "\(c)")
}
}
}
public extension Substring {
public subscript (i: Int) -> Character {
get {
return self[index(startIndex, offsetBy: i)]
}
set (c) {
let n = index(startIndex, offsetBy: i)
replaceSubrange(n...n, with: "\(c)")
}
        

}
public subscript (bounds: CountableRange<Int>) -> Substring {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start ..< end]
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ..< end, with: s)
}
}
public subscript (bounds: CountableClosedRange<Int>) -> Substring {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start ... end]
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ... end, with: s)
}
}
public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
return self[start ... end]
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
replaceSubrange(start ... end, with: s)
}
        

}
public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[startIndex ... end]
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ..< end, with: s)
}
}
public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[startIndex ..< end]
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ..< end, with: s)
}
}
public subscript (i: Int) -> String {
get {
return "\(self[index(startIndex, offsetBy: i)])"
}
set (c) {
let n = index(startIndex, offsetBy: i)
replaceSubrange(n...n, with: "\(c)")
}
}
public subscript (bounds: CountableRange<Int>) -> String {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[start ..< end])"
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ..< end, with: s)
}
}
public subscript (bounds: CountableClosedRange<Int>) -> String {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[start ... end])"
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(start ... end, with: s)
}
        

}
public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
get {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
return "\(self[start ... end])"
}
set (s) {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(endIndex, offsetBy: -1)
replaceSubrange(start ... end, with: s)
}
}
public subscript (bounds: PartialRangeThrough<Int>) -> String {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[startIndex ... end])"
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ... end, with: s)
}
}
public subscript (bounds: PartialRangeUpTo<Int>) -> String {
get {
let end = index(startIndex, offsetBy: bounds.upperBound)
return "\(self[startIndex ..< end])"
}
set (s) {
let end = index(startIndex, offsetBy: bounds.upperBound)
replaceSubrange(startIndex ..< end, with: s)
}
}
    

public subscript (i: Int) -> Substring {
get {
return Substring("\(self[index(startIndex, offsetBy: i)])")
}
set (c) {
let n = index(startIndex, offsetBy: i)
replaceSubrange(n...n, with: "\(c)")
}
}
}

斯威夫特4.2

这个答案是理想的,因为它将String及其所有Subsequences (Substring)扩展为一个扩展

public extension StringProtocol {
    

public subscript (i: Int) -> Element {
return self[index(startIndex, offsetBy: i)]
}


public subscript (bounds: CountableClosedRange<Int>) -> SubSequence {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start...end]
}
    

public subscript (bounds: CountableRange<Int>) -> SubSequence {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start..<end]
}
    

public subscript (bounds: PartialRangeUpTo<Int>) -> SubSequence {
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[startIndex..<end]
}
    

public subscript (bounds: PartialRangeThrough<Int>) -> SubSequence {
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[startIndex...end]
}
    

public subscript (bounds: CountablePartialRangeFrom<Int>) -> SubSequence {
let start = index(startIndex, offsetBy: bounds.lowerBound)
return self[start..<endIndex]
}
}

使用

var str = "Hello, playground"


print(str[5...][...5][0])
// Prints ","

我是斯威夫特4号

let myString = "LOVE"


self.textField1.text = String(Array(myString)[0])
self.textField2.text = String(Array(myString)[1])
self.textField3.text = String(Array(myString)[2])
self.textField4.text = String(Array(myString)[3])

这是最好最简单的方法之一

        let yourString = "thisString"
print(Array(yourString)[8])

将字符串中的每个字母放入数组 然后选择第9个

你可以通过将字符串转换为数组,并通过下标获得特定的索引,如下所示

var str = "Hello"
let s = Array(str)[2]
print(s)

斯威夫特5.1

这可能是所有答案中最简单的一个。

添加这个扩展:

extension String {
func retrieveFirstCharacter() -> String? {
guard self.count > 0 else { return nil }
let numberOfCharacters = self.count
return String(self.dropLast(numberOfCharacters - 1))
}
}

到目前为止,下标(_:)不可用。就像我们不能这么做一样

str[0]
用绳子< p >。我们必须提供"String "。指数” 但是,我们怎么用这种方式给出我们自己的索引号呢,我们可以用

string[str.index(str.startIndex, offsetBy: 0)]

在Swift 5中,没有扩展到String:

var str = "ABCDEFGH"
for char in str {
if(char == "C") { }
}

上述Swift代码与Java代码相同:

int n = 8;
var str = "ABCDEFGH"
for (int i=0; i<n; i++) {
if (str.charAt(i) == 'C') { }
}

斯威夫特5.1.3:

添加一个String扩展名:

extension String {


func stringAt(_ i: Int) -> String {
return String(Array(self)[i])
}


func charAt(_ i: Int) -> Character {
return Array(self)[i]
}
}


let str = "Teja Kumar"
let str1: String = str.stringAt(2)  //"j"
let str2: Character = str.charAt(5)  //"k"

对我来说最有效的方法是:

var firstName = "Olivia"
var lastName = "Pope"


var nameInitials.text = "\(firstName.prefix(1))" + "\    (lastName.prefix(1))"

输出:“OP"

斯威夫特5.3

我觉得这很优雅。保罗·哈德森的“黑客与斯威夫特”的荣誉;对于这个解决方案:

@available (macOS 10.15, * )
extension String {
subscript(idx: Int) -> String {
String(self[index(startIndex, offsetBy: idx)])
}
}


然后,要从字符串中获取一个字符,你只需做:

var string = "Hello, world!"


var firstChar = string[0] // No error, returns "H" as a String

注意:我只是想补充,这将返回String,正如在评论中指出的那样。我认为这对Swift用户来说可能是意想不到的,但我经常需要String来直接在我的代码中使用,而不是Character类型,所以它确实简化了我的代码,避免了后来从字符到字符串的转换。

下标在这里很有用

但是字符串下标将把参数作为字符串。索引,所以很多人都搞不懂如何传递字符串。索引以获取如何形成字符串的详细信息。索引根据我们的要求,请参阅以下文件苹果公司的文档

在这里,我创建了一个扩展方法来获取字符串中的第n个字符

extension String {
subscript(i: Int) -> String {
return  i < count ? String(self[index(startIndex, offsetBy: i)]) : ""
}
}

使用

let name = "Narayana Rao"
print(name[11]) //o
print(name[1]) //a
print(name[0]) //N
print(name[30]) //""

如果你传递的索引超出了字符串计数的范围,它将返回空字符串