在 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: Rangereturn 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 类型下标时崩溃。对于不会因超出范围值而崩溃的范围的下标,您可以使用implementationStringProtocol
没有成功,因为index
方法在那里不存在。
为什么不是内置的?
错误消息显示“请参阅文档评论以进行讨论”。苹果在文件UnavailableStringAPIs.swift中提供了如下解释:
无法使用整数下标字符串。
“字符串中的
i
th 个字符”的概念有 不同库和系统中的不同解释 成分。应该选择正确的解释 根据用例和所涉及的API,所以String
下标不能为整数。Swift 提供了几种不同的方式来访问字符 存储在字符串中的数据。
String.utf8
是 UTF-8 代码单元的集合 细绳。将字符串转换为 UTF-8 时使用此 API。 大多数 POSIX API 以 UTF-8 代码单元处理字符串。
String.utf16
是 UTF-16 代码单元的集合 细绳。大多数 Cocoa 和 Cocoa touch API 在 UTF-16 代码单元的术语。例如,实例NSRange
与NSAttributedString
和NSRegularExpression
将子字符串的偏移量和长度存储在 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.Index
和 Int
不兼容。
如果您看到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) -> Element get return self[index(startIndex, offsetBy: offset)] set let start = index(startIndex, offsetBy: offset) replaceSubrange(start..<index(after: start), with: [newValue])
这应该是内置函数【参考方案7】:
Swift 4.2 或更高版本
使用String
的indices
属性的范围和部分范围下标
作为@LeoDabus nice answer 的变体,我们可以为DefaultIndices
添加一个额外的扩展,目的是让我们在实现自定义下标时可以使用String
的indices
属性(通过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
偏移两个索引(start
和end
)。您可以简单地使用 range.count 偏移end
索引并偏移start
索引【参考方案16】:
获取和设置下标(字符串和子字符串) - Swift 4.2
Swift 4.2,Xcode 10
我的回答基于@alecarlson 的回答。
唯一的大区别是您可以获得Substring
或String
返回(在某些情况下,单个Character
)。 你也可以get
和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)")
【讨论】:
这不必要地从 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 ..
现在是 ..<
(在你分配给 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 个字符的主要内容,如果未能解决你的问题,请参考以下文章