在 Swift 编程语言中获取字符串的第 n 个字符

Posted

技术标签:

【中文标题】在 Swift 编程语言中获取字符串的第 n 个字符【英文标题】:Get nth character of a string in Swift programming language 【发布时间】:2014-07-28 09:01:56 【问题描述】:

如何获取字符串的第 n 个字符?我尝试了括号([])访问器,但没有成功。

var string = "Hello, world!"

var firstChar = string[0] // Throws error

错误:“下标”不可用:无法使用 Int 为字符串下标,请参阅文档注释进行讨论

【问题讨论】:

错误信息“cannot subscript String with an Int, see the documentation comment for Discussion”似乎是指github.com/apple/swift/blob/master/stdlib/public/core/… 改用var firstChar = string.index(string.startIndex, offsetBy: 0) @SazzadHissainKhan 这将导致字符串索引,而不是字符。顺便说一句,为什么不简单地string.startIndex?对于第一个字符string[string.startIndex] 或只是string.first。请注意,您需要首先检查字符串是否为空的第一种方法,第二种方法返回一个可选的 【参考方案1】:

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

【讨论】:

请问什么是“self[index(startIndex, offsetBy: i)]”? “self[i]”是如何工作的? 嗨,Leo,感谢您的解决方案!我刚刚(今天)从 Swift 2.3 切换到 3 并且您的解决方案 subscript(range: Range) 给出了错误“Extra argument 'limitedBy' in call”。你觉得哪里有问题? @AhmetAkkök 你确定你没有更改代码吗? @Leo 原来我没有转换整个项目,但在应用程序而不是扩展程序上,我已经为应用程序和扩展程序重复了这个过程,现在它工作正常。非常感谢您的帮助! 这是非常复杂的代码。与在 Swift 3 中使用 return String(Array(characters)[range]) 相比有什么优势?【参考方案2】:

斯威夫特 5.3

我认为这非常优雅。 Paul Hudson 对“Hacking with Swift”这个解决方案的赞誉:

@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,正如 cmets 中所指出的那样。我认为这对 Swift 用户来说可能是出乎意料的,但我通常需要一个 String 来立即在我的代码中使用而不是 Character 类型,所以它确实简化了我的代码,避免了以后从 Character 到 String 的转换.

【讨论】:

这样做的时间复杂度是多少? 时间复杂度和let firstChar = string[string.index(string.startIndex, offsetBy: 0)]代码里做的一样 这正是在接受的答案中所做的。唯一的区别是您正在扩展 String 而不是 StringProtocol (它也支持子字符串)并返回一个字符串而不是一个字符,考虑到它应该返回在这种情况下是一个字符的集合元素,这是完全出乎意料的【参考方案3】:

对我最有效的方法是:

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

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

输出:“OP”

【讨论】:

【参考方案4】:

注意:请参阅Leo Dabus' answer,了解 Swift 4 和 Swift 5 的正确实现。

Swift 4 或更高版本

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

试试看here

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 类型下标时崩溃。对于不会因超出范围值而崩溃的范围的下标,您可以使用implementation


为什么不是内置的?

错误消息显示“请参阅文档评论以进行讨论”。苹果在文件UnavailableStringAPIs.swift中提供了如下解释:

无法使用整数下标字符串。

“字符串中的ith 个字符”的概念有 不同库和系统中的不同解释 成分。应该选择正确的解释 根据用例和所涉及的API,所以String 下标不能为整数。

Swift 提供了几种不同的方式来访问字符 存储在字符串中的数据。

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

String.utf16 是 UTF-16 代码单元的集合 细绳。大多数 Cocoa 和 Cocoa touch API 在 UTF-16 代码单元的术语。例如,实例 NSRangeNSAttributedStringNSRegularExpression 将子字符串的偏移量和长度存储在 UTF-16 代码单元的术语。

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

String.characters 是扩展字形的集合 集群,它们是用户感知的近似值 字符。

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

【讨论】:

Cannot find an overload for 'advance' that accepts an argument list of type '(String.Index, T)' ... String.IndexInt 不兼容。 如果您看到Cannot subscript a value of type 'String'...,请查看此答案:***.com/a/31265316/649379 当我尝试使用它时,我得到Ambiguous use of 'subscript' 警告!下面的扩展非常低效。每次使用整数访问字符串时,都会运行一个 O(n) 函数来推进其起始索引。在另一个线性循环中运行一个线性循环意味着这个 for 循环意外地是 O(n2) - 随着字符串长度的增加,这个循环所花费的时间呈二次方增加。而不是这样做,您可以使用字符的字符串集合。 fatal error: Can't form a Character from an empty String【参考方案5】:

斯威夫特 5.1.3:

添加字符串扩展:

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"

【讨论】:

每次调用此属性以从中提取单个字符时,这会将整个字符串转换为字符数组。【参考方案6】:

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

您需要将此字符串扩展添加到您的项目中(它已经过全面测试):

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 总是对这个问题有开箱即用的解决方案(没有我在下面提供的 String 扩展),我仍然会强烈推荐使用该扩展。为什么?因为它节省了我从 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"

【讨论】:

range.upperBound - range.lowerBound更改为range.count 这不是原始问题的一部分,但是......如果这个也支持分配会很好。例如,s[i] = "a" :)。 我相信 Swift 4.2 下标不再可用。我收到一条错误消息:“下标”不可用:无法使用 Int 为字符串下标,请参阅文档评论以进行讨论 @ChrisPrince extension StringProtocol where Self: RangeReplaceableCollection subscript(offset: Int) -&gt; Element get return self[index(startIndex, offsetBy: offset)] set let start = index(startIndex, offsetBy: offset) replaceSubrange(start..&lt;index(after: start), with: [newValue]) 这应该是内置函数【参考方案7】:

Swift 4.2 或更高版本

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

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

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 下标的(其他)替代方案!

【讨论】:

唯一的缺点是 CountableClosedRange 会从 startIndex 偏移两个索引 ***.com/a/38215613/4573247 现在扩展了 StringProtocol 以支持子字符串 @LeoDabus 我明白了。是的,主要是 linux,但现在很少使用 Swift:/ 我使用 swiftenv,不过,我想它也会很快用 4.2 更新。 @LeoDabus 感谢您将此答案更新为现代 Swift! @LeoDabus 干得好!稍后将不得不研究细节,但我确实记得我从不喜欢我们不得不依靠 Foundation 的一些有序/可数集合类型。【参考方案8】:

在没有扩展的 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')  

【讨论】:

【参考方案9】:

现在,下标(_:) 不可用。以及我们不能这样做

str[0] 

使用字符串。我们必须提供“String.Index” 但是,我们怎样才能以这种方式给出我们自己的索引号,而不是我们可以使用,

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

【讨论】:

请编辑您的答案并通过解释您的答案如何解决问题来添加一些上下文,而不是发布仅代码的答案。 From Review 为什么要进行不必要的偏移?为什么不简单地string[string.startIndex]?顺便说一句,代码将无法正确运行/编译,因为您使用了两个不同的变量名。【参考方案10】:

斯威夫特 5.1

这可能是所有这些答案中最简单的解决方案。

添加这个扩展:

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

【讨论】:

不应该一个名为retrieveFirstCharacter的方法返回一个Character吗?【参考方案11】:

您可以通过将字符串转换为数组并使用下标通过特定索引获取它,如下所示

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

【讨论】:

请注意,此解决方案会导致内容重复,从而降低内存和 CPU 的性能。【参考方案12】:

我非常简单的解决方案:

Swift 4.1:

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

Swift 5.1:

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

【讨论】:

在 Swift 4.1 中工作 最简单的解决方案,现在使用 Swift 5 示例 :) @Linh Dao 不要使用encodedOffset。 encodedOffset 已弃用:encodedOffset 已弃用,因为最常见的用法不正确。 @OhadM 最简单并不意味着它是正确的,或者至少它不会像你期望的那样工作试试let flags = "????"flags[String.Index(utf16Offset: 4, in: flags)] // "??" @OhadM 我的评论只是一个警告。如果您认为它的行为符合您的预期,请随意使用它。【参考方案13】:

探索最好和最简单的方法之一

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

将字符串的每个字母放入数组中 然后你卖掉第 9 个

【讨论】:

Sreekanth G、Matt Le Fleur 和其他人已经给出了相同的解决方案。而且您的版本更糟,因为它不会将结果转换回字符串。 但不必由人来决定他们想对结果做什么 我明白你说的。但我评论的第二部分只是对第一部分的补充,这是真正重要的部分:这个解决方案已经在其他答案中给出。请不要发布已经发布的内容。不要发布重复的内容,这就是我要说的。 puts each letters of your string into arrrays 已经是 Sreekanth G 和其他人给出的解决方案。字面意思一样。 对于像这样的简单任务,该解决方案会带来性能问题,因为字符串的全部内容将在内存中复制。【参考方案14】:

检查这是 Swift 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])

【讨论】:

【参考方案15】:

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

【讨论】:

这会不必要地从startIndex 偏移两个索引(startend)。您可以简单地使用 range.count 偏移end 索引并偏移start 索引【参考方案16】:

获取和设置下标(字符串和子字符串) - Swift 4.2

Swift 4.2,Xcode 10

我的回答基于@alecarlson 的回答。 唯一的大区别是您可以获得SubstringString 返回(在某些情况下,单个Character)。 你也可以getset下标。 最后,我的比@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)")
        
    

【讨论】:

这不必要地从 startIndex 偏移两个索引(开始和结束)。您可以简单地使用 range.count 偏移结束索引并偏移开始索引【参考方案17】:

Swift3

您可以使用下标语法来访问特定字符串索引处的字符。

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

或者我们可以在 Swift 4

中做一个字符串扩展
extension String 
    func getCharAtIndex(_ index: Int) -> Character 
        return self[self.index(self.startIndex, offsetBy: index)]
    

用法:

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

【讨论】:

【参考方案18】:

获取第一个字母:

first(str) // retrieve first letter

更多: http://sketchytech.blogspot.com/2014/08/swift-pure-swift-method-for-returning.html

【讨论】:

【参考方案19】:

在你的项目中包含这个扩展

  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

【讨论】:

【参考方案20】:

斯威夫特 4

String(Array(stringToIndex)[index]) 

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

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

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

Swift 不允许像数组一样对字符串进行索引,但这可以完成工作,蛮力风格。

【讨论】:

将整个字符串内容复制到另一个内存位置会适得其反,尤其是对于大字符串。我们不需要为直接内存访问等简单任务分配额外的内存。【参考方案21】:

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

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

【讨论】:

【参考方案22】:

还有一个替代方案,在 String manifesto 中进行了解释

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

【讨论】:

【参考方案23】:

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

Swift 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]

Swift 2.x

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]

【讨论】:

String 索引对于字符串是唯一的。这是因为不同的字符串可能具有不同的多单元 UTF-16 Characters 和/或在不同的位置,因此 UTF-16 单元索引将不匹配,可能超出多单元 UTF-16 @ 内的结尾或点987654329@. @Zaph 这很明显。 解释你为什么说:“有时它会崩溃或导致未定义的行为”。也许最好说不要这样做,因为...... @Sulthan .. 现在是 ..&lt;(在你分配给 range 的任务中) @CajunLuke 我知道你发布这条评论已经有一段时间了,但请看看this answer。你可以使用var lastChar = string[string.endIndex.predecessor()]【参考方案24】:

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

【讨论】:

【参考方案25】:

Swift 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

【讨论】:

【参考方案26】:

这是一个您可以使用的扩展,可与 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"

【讨论】:

创建一个Array 只是为了访问一个元素似乎是过度设计,并且还具有性能成本,因为字符串内容必须在内存中复制。【参考方案27】:

允许负指数

在使用下标扩展时,不必总是写string[string.length - 1] 来获取最后一个字符,这总是有用的。这个 (Swift 3) 扩展允许负索引、Range 和 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 "" 
    ...

【讨论】:

【参考方案28】:

使用字符就可以了。您可以快速将 String 转换为可由 CharacterView 方法操作的字符数组。

例子:

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

(完整的CharacterView doc)

(在 Swift 3 中测试)

【讨论】:

【参考方案29】:

如果您看到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/

【讨论】:

【参考方案30】:

在没有对 String 类的扩展的 Swift 3 中,尽可能简单!

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

在本例中,myCharacter 为“3”。

【讨论】:

以上是关于在 Swift 编程语言中获取字符串的第 n 个字符的主要内容,如果未能解决你的问题,请参考以下文章

Swift:如何在 plist 中获取第一个数组字符串?

Swift3.0语言教程获取字符串编码与哈希地址

Swift字符串截取与Range使用

在 Swift 中获取列表的第一项 [关闭]

获取 Swift 数组中的第一个条目

Swift3.0语言教程获取C字符串