ios Swift:如何从字符的开始到最后一个索引获取子字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28182441/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swift: How to get substring from start to last index of character
提问by Jason Hocker
I want to learn the best/simplest way to turn a string into another string but with only a subset, starting at the beginning and going to the last index of a character.
我想学习将字符串转换为另一个字符串的最佳/最简单的方法,但只有一个子集,从字符的开头开始到最后一个索引。
For example, convert "www.stackoverflow.com" to "www.stackoverflow". What code snippet would do that, and being the most swift-like? (I hope this doesn't bring a debate, but I can't find good lesson on how to handle substrings in Swift.
例如,将“www.stackoverflow.com”转换为“www.stackoverflow”。什么代码片段会做到这一点,并且是最快速的?(我希望这不会引起争论,但我找不到关于如何在 Swift 中处理子字符串的好课程。
回答by fpg1503
Just accessing backward
只是向后访问
The best way is to use substringToIndex
combined to the endIndex
property and the advance
global function.
最好的方法是substringToIndex
结合使用endIndex
属性和advance
全局函数。
var string1 = "www.stackoverflow.com"
var index1 = advance(string1.endIndex, -4)
var substring1 = string1.substringToIndex(index1)
Looking for a string starting from the back
寻找从后面开始的字符串
Use rangeOfString
and set options
to .BackwardsSearch
使用rangeOfString
并设置options
为.BackwardsSearch
var string2 = "www.stackoverflow.com"
var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex
var substring2 = string2.substringToIndex(index2!)
No extensions, pure idiomatic Swift
没有扩展,纯惯用 Swift
Swift 2.0
斯威夫特 2.0
advance
is now a part of Index
and is called advancedBy
. You do it like:
advance
现在是 的一部分Index
并被称为advancedBy
。你这样做:
var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
Swift 3.0
斯威夫特 3.0
You can't call advancedBy
on a String
because it has variable size elements. You have to use index(_, offsetBy:)
.
您不能调用advancedBy
aString
因为它具有可变大小的元素。你必须使用index(_, offsetBy:)
.
var string1 = "www.stackoverflow.com"
var index1 = string1.index(string1.endIndex, offsetBy: -4)
var substring1 = string1.substring(to: index1)
A lot of things have been renamed. The cases are written in camelCase, startIndex
became lowerBound
.
很多东西都改名了。这些案例是用驼峰式写成的,startIndex
变成了lowerBound
.
var string2 = "www.stackoverflow.com"
var index2 = string2.range(of: ".", options: .backwards)?.lowerBound
var substring2 = string2.substring(to: index2!)
Also, I wouldn't recommend force unwrapping index2
. You can use optional binding or map
. Personally, I prefer using map
:
另外,我不建议 force unwrapping index2
。您可以使用可选绑定或map
. 就个人而言,我更喜欢使用map
:
var substring3 = index2.map(string2.substring(to:))
Swift 4
斯威夫特 4
The Swift 3 version is still valid but now you can now use subscripts with indexes ranges:
Swift 3 版本仍然有效,但现在您可以使用带有索引范围的下标:
let string1 = "www.stackoverflow.com"
let index1 = string1.index(string1.endIndex, offsetBy: -4)
let substring1 = string1[..<index1]
The second approach remains unchanged:
第二种方法保持不变:
let string2 = "www.stackoverflow.com"
let index2 = string2.range(of: ".", options: .backwards)?.lowerBound
let substring3 = index2.map(string2.substring(to:))
回答by serg_zhd
Swift 3, XCode 8
斯威夫特 3,XCode 8
func lastIndexOfCharacter(_ c: Character) -> Int? {
return range(of: String(c), options: .backwards)?.lowerBound.encodedOffset
}
Since advancedBy(Int)
is gone since Swift 3 use String
's method index(String.Index, Int)
. Check out this String
extension with substring and friends:
自从advancedBy(Int)
Swift 3 useString
的方法以来就消失了index(String.Index, Int)
。String
使用 substring 和朋友查看此扩展:
public extension String {
//right is the first encountered string after left
func between(_ left: String, _ right: String) -> String? {
guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
, leftRange.upperBound <= rightRange.lowerBound
else { return nil }
let sub = self.substring(from: leftRange.upperBound)
let closestToLeftRange = sub.range(of: right)!
return sub.substring(to: closestToLeftRange.lowerBound)
}
var length: Int {
get {
return self.characters.count
}
}
func substring(to : Int) -> String {
let toIndex = self.index(self.startIndex, offsetBy: to)
return self.substring(to: toIndex)
}
func substring(from : Int) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: from)
return self.substring(from: fromIndex)
}
func substring(_ r: Range<Int>) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
return self.substring(with: Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex)))
}
func character(_ at: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: at)]
}
func lastIndexOfCharacter(_ c: Character) -> Int? {
guard let index = range(of: String(c), options: .backwards)?.lowerBound else
{ return nil }
return distance(from: startIndex, to: index)
}
}
UPDATED extension for Swift 4
Swift 4 的更新扩展
public extension String {
//right is the first encountered string after left
func between(_ left: String, _ right: String) -> String? {
guard
let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
, leftRange.upperBound <= rightRange.lowerBound
else { return nil }
let sub = self[leftRange.upperBound...]
let closestToLeftRange = sub.range(of: right)!
return String(sub[..<closestToLeftRange.lowerBound])
}
var length: Int {
get {
return self.count
}
}
func substring(to : Int) -> String {
let toIndex = self.index(self.startIndex, offsetBy: to)
return String(self[...toIndex])
}
func substring(from : Int) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: from)
return String(self[fromIndex...])
}
func substring(_ r: Range<Int>) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
let indexRange = Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))
return String(self[indexRange])
}
func character(_ at: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: at)]
}
func lastIndexOfCharacter(_ c: Character) -> Int? {
guard let index = range(of: String(c), options: .backwards)?.lowerBound else
{ return nil }
return distance(from: startIndex, to: index)
}
}
Usage:
用法:
let text = "www.stackoverflow.com"
let at = text.character(3) // .
let range = text.substring(0..<3) // www
let from = text.substring(from: 4) // stackoverflow.com
let to = text.substring(to: 16) // www.stackoverflow
let between = text.between(".", ".") // stackoverflow
let substringToLastIndexOfChar = text.lastIndexOfCharacter(".") // 17
P.S. It's really odd that developers forced to deal with String.Index
instead of plain Int
. Why should we bother about internal String
mechanics and not just have simple substring()
methods?
PS 开发人员被迫处理String.Index
而不是普通Int
. 为什么我们要关心内部String
机制而不是简单的substring()
方法?
回答by Marián ?erny
I would do it using a subscript (s[start..<end]
):
我会使用下标 ( s[start..<end]
)来做到这一点:
Swift 3, 4, 5
斯威夫特 3、4、5
let s = "www.stackoverflow.com"
let start = s.startIndex
let end = s.index(s.endIndex, offsetBy: -4)
let substring = s[start..<end] // www.stackoverflow
回答by Leo Dabus
edit/update:
编辑/更新:
In Swift 4 or later(Xcode 10.0+) you can use the new BidirectionalCollectionmethod lastIndex(of:)
在Swift 4 或更高版本(Xcode 10.0+) 中,您可以使用新的BidirectionalCollection方法lastIndex(of:)
func lastIndex(of element: Element) -> Int?
let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
let subString = string[..<lastIndex] // "www.stackoverflow"
}
回答by joelparkerhenderson
Here's how I do it. You could do it the same way, or use this code for ideas.
这是我如何做到的。你可以用同样的方式来做,或者使用这个代码来获得想法。
let s = "www.stackoverflow.com"
s.substringWithRange(0..<s.lastIndexOf("."))
Here are the extensions I use:
以下是我使用的扩展:
import Foundation
extension String {
var length: Int {
get {
return countElements(self)
}
}
func indexOf(target: String) -> Int {
var range = self.rangeOfString(target)
if let range = range {
return distance(self.startIndex, range.startIndex)
} else {
return -1
}
}
func indexOf(target: String, startIndex: Int) -> Int {
var startRange = advance(self.startIndex, startIndex)
var range = self.rangeOfString(target, options: NSStringCompareOptions.LiteralSearch, range: Range<String.Index>(start: startRange, end: self.endIndex))
if let range = range {
return distance(self.startIndex, range.startIndex)
} else {
return -1
}
}
func lastIndexOf(target: String) -> Int {
var index = -1
var stepIndex = self.indexOf(target)
while stepIndex > -1 {
index = stepIndex
if stepIndex + target.length < self.length {
stepIndex = indexOf(target, startIndex: stepIndex + target.length)
} else {
stepIndex = -1
}
}
return index
}
func substringWithRange(range:Range<Int>) -> String {
let start = advance(self.startIndex, range.startIndex)
let end = advance(self.startIndex, range.endIndex)
return self.substringWithRange(start..<end)
}
}
Credit albertbori / Common Swift String Extensions
Generally I am a strong proponent of extensions, especially for needs like string manipulation, searching, and slicing.
一般来说,我是扩展的强烈支持者,尤其是对于字符串操作、搜索和切片等需求。
回答by rintaro
String
has builtin substring feature:
String
具有内置子字符串功能:
extension String : Sliceable {
subscript (subRange: Range<String.Index>) -> String { get }
}
If what you want is "going to the firstindex of a character", you can get the substring using builtin find()
function:
如果您想要的是“转到字符的第一个索引”,则可以使用内置find()
函数获取子字符串:
var str = "www.stackexchange.com"
str[str.startIndex ..< find(str, ".")!] // -> "www"
To find lastindex, we can implement findLast()
.
要找到最后一个索引,我们可以实现findLast()
.
/// Returns the last index where `value` appears in `domain` or `nil` if
/// `value` is not found.
///
/// Complexity: O(\ `countElements(domain)`\ )
func findLast<C: CollectionType where C.Generator.Element: Equatable>(domain: C, value: C.Generator.Element) -> C.Index? {
var last:C.Index? = nil
for i in domain.startIndex..<domain.endIndex {
if domain[i] == value {
last = i
}
}
return last
}
let str = "www.stackexchange.com"
let substring = map(findLast(str, ".")) { str[str.startIndex ..< func findLast<C: CollectionType where C.Generator.Element: Equatable, C.Index: BidirectionalIndexType>(domain: C, value: C.Generator.Element) -> C.Index? {
for i in lazy(domain.startIndex ..< domain.endIndex).reverse() {
if domain[i] == value {
return i
}
}
return nil
}
] } // as String?
// if "." is found, substring has some, otherwise `nil`
ADDED:
添加:
Maybe, BidirectionalIndexType
specialized version of findLast
is faster:
也许,BidirectionalIndexType
专业版findLast
更快:
extension String
{
func substringFromIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringFromIndex(self.startIndex.advancedBy(index))
}
func substringToIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringToIndex(self.startIndex.advancedBy(index))
}
func substringWithRange(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
return self.substringWithRange(range)
}
func substringWithRange(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
return self.substringWithRange(range)
}
}
回答by ChikabuZ
You can use these extensions:
您可以使用这些扩展:
Swift 2.3
斯威夫特 2.3
extension String
{
func substring(from index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(from: self.characters.index(self.startIndex, offsetBy: index))
}
func substring(to index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
}
func substring(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: end)
let range = startIndex..<endIndex
return self.substring(with: range)
}
func substring(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
let range = startIndex..<endIndex
return self.substring(with: range)
}
}
Swift 3
斯威夫特 3
let string = "www.stackoverflow.com"
let substring = string.substringToIndex(string.characters.count-4)
Usage:
用法:
extension String {
/// the length of the string
var length: Int {
return self.characters.count
}
/// Get substring, e.g. "ABCDE".substring(index: 2, length: 3) -> "CDE"
///
/// - parameter index: the start index
/// - parameter length: the length of the substring
///
/// - returns: the substring
public func substring(index: Int, length: Int) -> String {
if self.length <= index {
return ""
}
let leftIndex = self.index(self.startIndex, offsetBy: index)
if self.length <= index + length {
return self.substring(from: leftIndex)
}
let rightIndex = self.index(self.endIndex, offsetBy: -(self.length - index - length))
return self.substring(with: leftIndex..<rightIndex)
}
/// Get substring, e.g. -> "ABCDE".substring(left: 0, right: 2) -> "ABC"
///
/// - parameter left: the start index
/// - parameter right: the end index
///
/// - returns: the substring
public func substring(left: Int, right: Int) -> String {
if length <= left {
return ""
}
let leftIndex = self.index(self.startIndex, offsetBy: left)
if length <= right {
return self.substring(from: leftIndex)
}
else {
let rightIndex = self.index(self.endIndex, offsetBy: -self.length + right + 1)
return self.substring(with: leftIndex..<rightIndex)
}
}
}
回答by Alexander Volkov
Swift 4:
斯威夫特 4:
print("test: " + String("ABCDE".substring(index: 2, length: 3) == "CDE"))
print("test: " + String("ABCDE".substring(index: 0, length: 3) == "ABC"))
print("test: " + String("ABCDE".substring(index: 2, length: 1000) == "CDE"))
print("test: " + String("ABCDE".substring(left: 0, right: 2) == "ABC"))
print("test: " + String("ABCDE".substring(left: 1, right: 3) == "BCD"))
print("test: " + String("ABCDE".substring(left: 3, right: 1000) == "DE"))
you can test it as follows:
您可以按如下方式进行测试:
import Foundation
let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
print(string.substringToIndex(rangeOfIndex.endIndex))
}
// prints "www.stackoverflow."
Check https://gitlab.com/seriyvolk83/SwiftExlibrary. It contains these and other helpful methods.
检查https://gitlab.com/seriyvolk83/SwiftEx库。它包含这些和其他有用的方法。
回答by Imanou Petit
Do you want to get a substring of a string from start index to the last index of one of its characters? If so, you may choose one of the following Swift 2.0+ methods.
你想得到一个字符串的子串,从起始索引到它的一个字符的最后一个索引吗?如果是这样,您可以选择以下 Swift 2.0+ 方法之一。
Methods that require Foundation
需要的方法 Foundation
Get a substring that includes the last index of a character:
获取包含字符的最后一个索引的子字符串:
import Foundation
let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
print(string.substringToIndex(rangeOfIndex.startIndex))
}
// prints "www.stackoverflow"
Get a substring that DOES NOT include the last index of a character:
获取不包含字符的最后一个索引的子字符串:
import Foundation
extension String {
func substringWithLastInstanceOf(character: Character) -> String? {
if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
return self.substringToIndex(rangeOfIndex.endIndex)
}
return nil
}
func substringWithoutLastInstanceOf(character: Character) -> String? {
if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
return self.substringToIndex(rangeOfIndex.startIndex)
}
return nil
}
}
print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))
/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/
If you need to repeat those operations, extending String
can be a good solution:
如果您需要重复这些操作,扩展String
可能是一个很好的解决方案:
let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
print(string[string.startIndex ..< reverseIndex.base])
}
// prints "www.stackoverflow."
Methods that DO NOT require Foundation
不需要的方法 Foundation
Get a substring that includes the last index of a character:
获取包含字符的最后一个索引的子字符串:
let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
print(string[string.startIndex ..< reverseIndex.base.advancedBy(-1)])
}
// prints "www.stackoverflow"
Get a substring that DOES NOT include the last index of a character:
获取不包含字符的最后一个索引的子字符串:
extension String {
func substringWithLastInstanceOf(character: Character) -> String? {
if let reverseIndex = characters.reverse().indexOf(".") {
return self[self.startIndex ..< reverseIndex.base]
}
return nil
}
func substringWithoutLastInstanceOf(character: Character) -> String? {
if let reverseIndex = characters.reverse().indexOf(".") {
return self[self.startIndex ..< reverseIndex.base.advancedBy(-1)]
}
return nil
}
}
print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))
/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/
If you need to repeat those operations, extending String
can be a good solution:
如果您需要重复这些操作,扩展String
可能是一个很好的解决方案:
extension String {
func index(at: Int) -> String.Index {
return self.index(self.startIndex, offsetBy: at)
}
}
回答by bauerMusic
The one thing that adds clatter is the repeated stringVar
:
增加咔嗒声的一件事是重复stringVar
:
stringVar[stringVar.index(stringVar.startIndex, offsetBy: ...)
stringVar[ stringVar.index( stringVar.startIndex, offsetBy: ...)
In Swift 4
在斯威夫特 4
An extension can reduce some of that:
扩展可以减少其中的一些:
let string = "abcde"
let to = string[..<string.index(at: 3)] // abc
let from = string[string.index(at: 3)...] // de
Then, usage:
然后,用法:
let backToString = String(from)
It should be noted that to
and from
are type Substring
(or String.SubSequance
). They do not allocate new strings and are more efficient for processing.
需要注意的是to
和from
是类型Substring
(或String.SubSequance
)。它们不分配新字符串并且处理效率更高。
To get back a String
type, Substring
needs to be casted back to String
:
要取回String
类型,Substring
需要将其强制转换为String
:
This is where a string is finally allocated.
这是最终分配字符串的地方。