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

Moh*_*sen 392 string collections character swift

如何获取字符串的第n个字符?我尝试了托架([])访问器没有运气.

var string = "Hello, world!"

var firstChar = string[0] // Throws error
Run Code Online (Sandbox Code Playgroud)

错误:'subscript'不可用:不能使用Int下标String,请参阅文档注释以供讨论

ale*_*son 549

注意:请参阅Leo Dabus关于Swift 4正确实施的答案.

斯威夫特4

SubstringSwift 4中引入了这种类型,通过与原始字符串共享存储来使子字符串更快,更高效,这就是下标函数应该返回的内容.

在这里尝试一下

extension String {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}
extension Substring {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}
Run Code Online (Sandbox Code Playgroud)

要将其转换Substring为a String,您可以简单地执行String(string[0..2]),但只有在计划保留子字符串时才应该这样做.否则,保持它更有效Substring.

如果有人能找到将这两个扩展合并为一个的好方法,那就太好了.我尝试扩展StringProtocol 但没有成功,因为index那里的方法不存在.

 

斯威夫特3:

extension String {
  subscript (i: Int) -> Character {
    return self[index(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[Range(start ..< end)]
  }
}
Run Code Online (Sandbox Code Playgroud)

 

为什么这不是内置的?

Apple提供以下解释(在此处找到):

使用整数订阅字符串不可用.

" i字符串中的第一个字符" 的概念在不同的库和系统组件中有不同的解释.应根据用例和所涉及的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与UTF-16代码单元一起使用NSAttributedStringNSRegularExpression存储子字符串偏移量和长度的实例 .

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

  • String.characters 是一组扩展的字形簇,它是用户感知字符的近似值.

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

  • 当我尝试使用它时,我会'不明确地使用'下标'. (24认同)
  • 警告!下面的扩展是非常低效的.每次使用整数访问字符串时,都会运行O(n)函数来提升其起始索引.在另一个线性循环内运行线性循环意味着这个for循环意外地为O(n2) - 随着字符串长度的增加,此循环所需的时间呈二次方增加.而不是这样做你可以使用字符的字符串集合. (18认同)
  • 如果你看到'不能下标类型'String'的值...``检查这个答案:http://stackoverflow.com/a/31265316/649379 (7认同)
  • `找不到'advance'的重载,它接受类型为'(String.Index,T)的参数列表'```String.Index`和`Int`不兼容. (4认同)
  • `致命错误:无法从空字符串形成一个字符 (2认同)

nal*_*exn 316

Swift 4.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"
Run Code Online (Sandbox Code Playgroud)

您需要将此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])
  }

}
Run Code Online (Sandbox Code Playgroud)

即使Swift总是有解决这个问题的解决方案(没有我在下面提供的String扩展),我仍然强烈建议使用扩展.为什么?因为它从早期版本的Swift中节省了数十小时的痛苦迁移,其中String的语法几乎每个版本都在变化,但我需要做的就是更新扩展的实现,而不是重构整个300k代码生产线.应用程序.做出你的选择.

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"
Run Code Online (Sandbox Code Playgroud)

  • 这应该是内置函数 (4认同)
  • 我相信Swift 4.2下载不再可用.我得到一个错误说:'subscript'不可用:不能使用Int下标String,请参阅文档注释以供讨论 (2认同)
  • @ChrisPrince`extension StringProtocol,其中Self:RangeReplaceableCollection {下标(offset:Int)-&gt;元素{get {return self [index(startIndex,offsetBy:offset)]}} set {let start = index(startIndex,offsetBy:offset)replaceSubrange( start .. &lt;index(after:start),with:[newValue])}}}` (2认同)

Jen*_*rth 136

我想出了这个整洁的解决方法

var firstChar = Array(string)[0]
Run Code Online (Sandbox Code Playgroud)

  • 这似乎非常低效,因为你只是为了得到第一个字符而复制整个字符串.使用字符串[string.Sulthan指出,startIndex]而不是0. (41认同)
  • 解包字符串:`var firstChar = Array(string!)[0]`否则会说`add arrayLiteral` (6认同)
  • 对于(常见)情况,这是一个很好的快速解决方法,您知道您有UTF8或ASCII编码的字符串.请确保字符串永远不会处于使用多个字节的编码中. (2认同)
  • 我不相信这很干净,事实上它是一个圆形的.我不太确定首先使用Array中的哪个初始化器导致这种情况发生(我假设它是SequenceType初始化器,导致它将字符串的字符作为Array的各个组件收集).这根本不明确,将来可能会在没有类型转换的情况下得到纠正.如果通过[string] .first使用数组的简写,这也不起作用.@Sulthan的解决方案最适合使用烘焙的索引值.这里发生的事情要清楚得多. (2认同)
  • 哇,编译器段错误! (2认同)

Sul*_*han 122

没有使用整数的索引,只使用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]
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

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

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]
Run Code Online (Sandbox Code Playgroud)

  • `String`索引对于字符串是唯一的.这是因为不同的字符串可能具有不同的多单元UTF-16"字符"和/或位于不同的位置,因此UTF-16单元索引将不匹配,可能会超出多单元UTF-16内的端点或点. Character`. (7认同)
  • 解释你为什么说:"有时它会崩溃或导致未定义的行为".也许最好说不要这样做因为...... (3认同)
  • @CajunLuke我知道你发布此评论已经有一段时间了,但看看[这个答案](http://stackoverflow.com/a/24122445/1203475).你可以使用`var lastChar = string [string.endIndex.predecessor()]` (3认同)

Leo*_*bus 109

Swift 4.1或更高版本

您可以扩展Swift 4的StringProtocol以使下标也可用于子字符串.注意:由于建议SE-0191,__CODE__可以删除扩展约束 :

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)) }
}
Run Code Online (Sandbox Code Playgroud)
extension LosslessStringConvertible {
    var string: String { .init(self) }
}
Run Code Online (Sandbox Code Playgroud)
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]
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

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 !!!"
Run Code Online (Sandbox Code Playgroud)


War*_*shi 60

斯威夫特4

let str = "My String"
Run Code Online (Sandbox Code Playgroud)

索引处的字符串

let index = str.index(str.startIndex, offsetBy: 3)
String(str[index])    // "S"
Run Code Online (Sandbox Code Playgroud)

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

前n个字符

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[..<startIndex])    // "My "
Run Code Online (Sandbox Code Playgroud)

最后n个字符

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[startIndex...])    // "String"
Run Code Online (Sandbox Code Playgroud)

斯威夫特2和3

str = "My String"
Run Code Online (Sandbox Code Playgroud)

**索引处的字符串**

斯威夫特2

let charAtIndex = String(str[str.startIndex.advancedBy(3)])  // charAtIndex = "S"
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

str[str.index(str.startIndex, offsetBy: 3)]
Run Code Online (Sandbox Code Playgroud)

SubString fromIndex toIndex

斯威夫特2

let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)] // subStr = "Strin"
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

str[str.index(str.startIndex, offsetBy: 3)...str.index(str.startIndex, offsetBy: 7)]
Run Code Online (Sandbox Code Playgroud)

前n个字符

let first2Chars = String(str.characters.prefix(2)) // first2Chars = "My"
Run Code Online (Sandbox Code Playgroud)

最后n个字符

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"
Run Code Online (Sandbox Code Playgroud)


Mat*_*eur 24

Swift 2.0从Xcode 7 GM Seed开始

var text = "Hello, world!"

let firstChar = text[text.startIndex.advancedBy(0)] // "H"
Run Code Online (Sandbox Code Playgroud)

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

编辑:Swift 3.0

text[text.index(text.startIndex, offsetBy: 0)]
Run Code Online (Sandbox Code Playgroud)


nb有更简单的方法来抓取字符串中的某些字符

例如 let firstChar = text.characters.first


Sof*_*ner 23

如果你看到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]
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特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]
    }
}
Run Code Online (Sandbox Code Playgroud)

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


mul*_*des 20

斯威夫特 5.3

我认为这是非常优雅的。对此解决方案的“Hacking with Swift”的 Paul Hudson 表示赞赏:

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

Run Code Online (Sandbox Code Playgroud)

然后要从 String 中取出一个字符,您只需执行以下操作:

var string = "Hello, world!"

var firstChar = string[0] // No error, returns "H" as a String
Run Code Online (Sandbox Code Playgroud)

注意:我只是想补充一下,这将返回String评论中指出的a 。我认为这对于 Swift 用户来说可能是意料之外的,但我经常需要String立即在我的代码中使用a而不是Character类型,所以它确实简化了我的代码,避免了以后从 Character 到 String 的转换。

  • 时间复杂度与在代码中使用 `let firstChar = string[string.index(string.startIndex, offsetBy: 0)]` 执行的时间复杂度相同 (2认同)

Dan*_*ieu 19

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]
    }
}
Run Code Online (Sandbox Code Playgroud)


dre*_*wag 12

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)!
Run Code Online (Sandbox Code Playgroud)

  • **不要使用`NSString`方法从Swift本地`String`访问单个字符 - 两者使用不同的计数机制,因此你会得到具有更高Unicode字符的不可预测的结果.第一种方法应该是安全的(一旦处理了Swift的Unicode错误). (4认同)
  • 你已经可以遍历字符串了:对于"foo"中的字母{println(letter)} (3认同)

Fré*_*dda 11

另外,有一些函数可以直接应用于String的Character-chain表示,如下所示:

var string = "Hello, playground"
let firstCharacter = string.characters.first // returns "H"
let lastCharacter = string.characters.last // returns "d"
Run Code Online (Sandbox Code Playgroud)

结果是Character类型,但您可以将其强制转换为String.

或这个:

let reversedString = String(string.characters.reverse())
// returns "dnuorgyalp ,olleH" 
Run Code Online (Sandbox Code Playgroud)

:-)


Har*_* G. 11

斯威夫特4

String(Array(stringToIndex)[index]) 
Run Code Online (Sandbox Code Playgroud)

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

示例String(Array("HelloThere")[1])将"e"作为String返回.

(Array("HelloThere")[1] 将"e"作为角色返回.

Swift不允许将字符串像数组一样编入索引,但这可以完成工作,蛮力风格.

  • 将整个字符串内容复制到另一个内存位置会适得其反,尤其是对于大字符串。我们不需要为直接内存访问等简单任务分配额外的内存。 (2认同)

小智 8

您可以通过将 String 转换为 Array 并使用下标通过特定索引获取它来做到这一点,如下所示

var str = "Hello"
let s = Array(str)[2]
print(s)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此解决方案将导致内容重复,从而降低内存和 CPU 的性能。 (3认同)

Lin*_*Dao 7

我非常简单的解决方案:

Swift 4.1:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]
Run Code Online (Sandbox Code Playgroud)

Swift 5.1:

let firstCharacter = myString[String.Index.init(utf16Offset: index, in: myString)]
Run Code Online (Sandbox Code Playgroud)


Nar*_*ana 7

我们有下标,这在这里非常有用

但是 String 下标会将参数作为 String.Index 所以大多数人都会在这里感到困惑如何传递 String.Index 来获取如何根据我们的要求形成 String.Index 的详细信息请查看下面的文档Apple 文档

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

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

用法

let name = "Narayana Rao Routhu"
print(name[11]) //o
print(name[1]) //a
print(name[0]) //N
print(name[30]) //""
Run Code Online (Sandbox Code Playgroud)

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


小智 5

我刚才有同样的问题.只需这样做:

var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)
Run Code Online (Sandbox Code Playgroud)


Ham*_*med 5

迅捷3

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

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

访问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)]
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

let foo = "ABC123"
foo.getCharAtIndex(2) //C
Run Code Online (Sandbox Code Playgroud)


Yod*_*ama 5

目前,下标(_:)不可用。我们也做不到这一点

str[0] 
Run Code Online (Sandbox Code Playgroud)

对于字符串。我们必须提供“String.Index”但是,我们如何以这种方式给出我们自己的索引号,我们可以使用,

string[str.index(str.startIndex, offsetBy: 0)]
Run Code Online (Sandbox Code Playgroud)


小智 5

在 Swift 5 中,无需扩展String

var str = "ABCDEFGH"
for char in str {
if(char == "C") { }
}
Run Code Online (Sandbox Code Playgroud)

上面的 Swift 代码与该代码相同Java

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