Sur*_*gch 316 string substring range swift
我一直在使用Swift 3更新我的一些旧代码和答案但是当我使用子字符串获取Swift字符串和索引时,事情变得令人困惑.
具体来说,我尝试以下方法:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
Run Code Online (Sandbox Code Playgroud)
第二行给我以下错误
'String'类型的值没有成员'substringWithRange'
我看到现在String
确实有以下方法:
str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)
Run Code Online (Sandbox Code Playgroud)
起初这些让我很困惑,所以我开始玩索引和范围.这是子串的后续问题和答案.我在下面添加一个答案来说明它们是如何使用的.
Sur*_*gch 753
以下所有示例均使用
var str = "Hello, playground"
Run Code Online (Sandbox Code Playgroud)
Strings在Swift 4中得到了相当大的改革.当你从String获得一些子串时,你会得到一个Substring
类型而不是一个类型String
.为什么是这样?字符串是Swift中的值类型.这意味着如果您使用一个String来创建一个String,则必须将其复制.这对稳定性有好处(没有其他人会在你不知情的情况下改变它)但对效率不利.
另一方面,Substring是一个返回原始String的引用.这是来自说明该文档的文档中的图像.
不需要复制,因此使用起来效率更高.但是,假设您从一百万个字符串中获得了十个字符的子串.因为Substring是引用String的,所以只要子字符串存在,系统就必须保持整个String.因此,每当您完成对子串的操作时,将其转换为String.
let myString = String(mySubstring)
Run Code Online (Sandbox Code Playgroud)
这将只复制子串,旧的String可以被垃圾收集.子串(作为一种类型)意味着短暂的.
Swift 4的另一个重大改进是Strings是Collections(再次).这意味着无论你对集合做什么,你都可以做一个String(使用下标,迭代字符,过滤等).
以下示例显示如何在Swift中获取子字符串.
您可以使用标或一些其他的方法获得一个字符串的子串(例如prefix
,suffix
,split
).但是,您仍然需要使用String.Index
而不是Int
该范围的索引.(如果你需要帮助,请参阅我的其他答案.)
你可以使用下标(注意Swift 4单侧范围):
let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello
Run Code Online (Sandbox Code Playgroud)
或者prefix
:
let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello
Run Code Online (Sandbox Code Playgroud)
甚至更容易:
let mySubstring = str.prefix(5) // Hello
Run Code Online (Sandbox Code Playgroud)
使用下标:
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground
Run Code Online (Sandbox Code Playgroud)
或者suffix
:
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground
Run Code Online (Sandbox Code Playgroud)
甚至更容易:
let mySubstring = str.suffix(10) // playground
Run Code Online (Sandbox Code Playgroud)
请注意,使用时suffix(from: index)
我必须使用从头到尾倒数-10
.只使用时suffix(x)
,这不是必需的,它只占用x
String 的最后一个字符.
我们再次在这里使用下标.
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
let mySubstring = str[range] // play
Run Code Online (Sandbox Code Playgroud)
Substring
为String
不要忘记,当您准备保存子字符串时,您应该将其转换为a,String
以便可以清除旧字符串的内存.
let myString = String(mySubstring)
Run Code Online (Sandbox Code Playgroud)
Int
索引扩展?Int
在阅读Airspeed Velocity和Ole Begemann 的文章Strings in Swift 3之后,我对使用基于索引的扩展犹豫不决.虽然在Swift 4中,Strings是集合,但Swift团队故意没有使用Int
索引.它仍然是String.Index
.这与Swift Characters由不同数量的Unicode代码点组成有关.必须为每个字符串唯一计算实际索引.
我不得不说,我希望Swift团队能够String.Index
在未来找到一种方法.但在他们之前,我选择使用他们的API.它帮助我记住String操作不仅仅是简单的Int
索引查找.
Cod*_*ent 164
我对Swift的String访问模型感到非常沮丧:一切都必须是Index
.我想要的只是访问字符串的第i个字符Int
,而不是笨拙的索引和推进(这恰好随着每个主要版本而变化).所以我做了一个扩展String
:
extension String {
func index(from: Int) -> Index {
return self.index(startIndex, offsetBy: from)
}
func substring(from: Int) -> String {
let fromIndex = index(from: from)
return substring(from: fromIndex)
}
func substring(to: Int) -> String {
let toIndex = index(from: to)
return substring(to: toIndex)
}
func substring(with r: Range<Int>) -> String {
let startIndex = index(from: r.lowerBound)
let endIndex = index(from: r.upperBound)
return substring(with: startIndex..<endIndex)
}
}
let str = "Hello, playground"
print(str.substring(from: 7)) // playground
print(str.substring(to: 5)) // Hello
print(str.substring(with: 7..<11)) // play
Run Code Online (Sandbox Code Playgroud)
Lou*_*ell 73
Swift 4扩展:
extension String {
subscript(_ range: CountableRange<Int>) -> String {
let idx1 = index(startIndex, offsetBy: max(0, range.lowerBound))
let idx2 = index(startIndex, offsetBy: min(self.count, range.upperBound))
return String(self[idx1..<idx2])
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
let s = "hello"
s[0..<3] // "hel"
s[3..<s.count] // "lo"
Run Code Online (Sandbox Code Playgroud)
或unicode:
let s = ""
s[0..<1] // ""
Run Code Online (Sandbox Code Playgroud)
geb*_*bel 19
在swift 4 String
符合Collection
.相反的substring
,我们现在应该使用subscript.
,如果你想切出只有两个字所以"play"
从"Hello, playground"
,你可以做这样的:
var str = "Hello, playground"
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let result = str[start..<end] // The result is of type Substring
Run Code Online (Sandbox Code Playgroud)
有趣的是,这样做会给你一个Substring
而不是一个String
.这是快速有效的,因为Substring
它与原始String共享其存储.但是,以这种方式共享内存也很容易导致内存泄漏.
这就是为什么要在清理原始String时将结果复制到新String中的原因.您可以使用普通构造函数执行此操作:
let newString = String(result)
Run Code Online (Sandbox Code Playgroud)
您可以Substring
在[Apple文档]中找到有关新类的更多信息.1
因此,如果您获得a Range
作为结果NSRegularExpression
,您可以使用以下扩展名:
extension String {
subscript(_ range: NSRange) -> String {
let start = self.index(self.startIndex, offsetBy: range.lowerBound)
let end = self.index(self.startIndex, offsetBy: range.upperBound)
let subString = self[start..<end]
return String(subString)
}
}
Run Code Online (Sandbox Code Playgroud)
Sou*_*HDI 15
Swift 4和5:
extension String {
subscript(_ i: Int) -> String {
let idx1 = index(startIndex, offsetBy: i)
let idx2 = index(idx1, offsetBy: 1)
return String(self[idx1..<idx2])
}
subscript (r: Range<Int>) -> String {
let start = index(startIndex, offsetBy: r.lowerBound)
let end = index(startIndex, offsetBy: r.upperBound)
return String(self[start ..< end])
}
subscript (r: CountableClosedRange<Int>) -> String {
let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound)
return String(self[startIndex...endIndex])
}
}
Run Code Online (Sandbox Code Playgroud)
如何使用它:
“ abcde” [0]->“ a”
“ abcde” [0 ... 2]->“ abc”
“ abcde” [2 .. <4]->“ cd”
遇到了这种相当短而简单的方法来实现这一目标。
var str = "Hello, World"
let arrStr = Array(str)
print(arrStr[0..<5]) //["H", "e", "l", "l", "o"]
print(arrStr[7..<12]) //["W", "o", "r", "l", "d"]
print(String(arrStr[0..<5])) //Hello
print(String(arrStr[7..<12])) //World
Run Code Online (Sandbox Code Playgroud)
我的思维很机械。以下是基础知识...
斯威夫特 4 斯威夫特 5
let t = "abracadabra"
let start1 = t.index(t.startIndex, offsetBy:0)
let end1 = t.index(t.endIndex, offsetBy:-5)
let start2 = t.index(t.endIndex, offsetBy:-5)
let end2 = t.index(t.endIndex, offsetBy:0)
let t2 = t[start1 ..< end1]
let t3 = t[start2 ..< end2]
//or a shorter form
let t4 = t[..<end1]
let t5 = t[start2...]
print("\(t2) \(t3) \(t)")
print("\(t4) \(t5) \(t)")
// result:
// abraca dabra abracadabra
Run Code Online (Sandbox Code Playgroud)
结果是一个子字符串,这意味着它是原始字符串的一部分。要获得完整的单独字符串,只需使用例如
String(t3)
String(t4)
Run Code Online (Sandbox Code Playgroud)
这是我使用的:
let mid = t.index(t.endIndex, offsetBy:-5)
let firstHalf = t[..<mid]
let secondHalf = t[mid...]
Run Code Online (Sandbox Code Playgroud)
小智 7
我有同样的初步反应.我也对每个主要版本中语法和对象如此剧烈变化感到沮丧.
然而,我从经验中意识到,我总是最终会遭遇试图打击"改变"的后果,就像处理多字节字符一样,如果你正在关注全球观众,这是不可避免的.
因此,我决定承认并尊重Apple工程师所做的努力,并在他们提出这种"恐怖"方法时理解他们的心态.
而不是创建扩展只是一种变通方法,以使您的生活更轻松(我不是说他们错了或昂贵),为什么不弄清楚Strings现在如何设计工作.
例如,我有这个代码正在使用Swift 2.2:
let rString = cString.substringToIndex(2)
let gString = (cString.substringFromIndex(2) as NSString).substringToIndex(2)
let bString = (cString.substringFromIndex(4) as NSString).substringToIndex(2)
Run Code Online (Sandbox Code Playgroud)
在放弃尝试使用相同的方法工作之后,例如使用Substrings,我终于理解了将Strings视为双向集合的概念,我最终得到了相同代码的这个版本:
let rString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let gString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let bString = String(cString.characters.prefix(2))
Run Code Online (Sandbox Code Playgroud)
我希望这有助于......
这是一个函数,它在提供开始和结束索引时返回给定子字符串的子字符串.如需完整参考,请访问以下链接.
func substring(string: String, fromIndex: Int, toIndex: Int) -> String? {
if fromIndex < toIndex && toIndex < string.count /*use string.characters.count for swift3*/{
let startIndex = string.index(string.startIndex, offsetBy: fromIndex)
let endIndex = string.index(string.startIndex, offsetBy: toIndex)
return String(string[startIndex..<endIndex])
}else{
return nil
}
}
Run Code Online (Sandbox Code Playgroud)
这是我创建的博客文章的链接,用于处理swift中的字符串操作. swift中的字符串操作(也包括swift 4)
小智 7
// 想象一下,需要从 2 中生成子字符串,长度为 3
let s = "abcdef"
let subs = s.suffix(s.count-2).prefix(3)
Run Code Online (Sandbox Code Playgroud)
// 现在 subs = "cde"
我创建了一个像这样的简单函数:
func sliceString(str: String, start: Int, end: Int) -> String {
let data = Array(str)
return String(data[start..<end])
}
Run Code Online (Sandbox Code Playgroud)
你可以通过以下方式使用它
print(sliceString(str: "0123456789", start: 0, end: 3)) // -> prints 012
Run Code Online (Sandbox Code Playgroud)
同样的挫败感,这应该没那么难……
我编译了这个从较大文本中获取子字符串位置的示例:
//
// Play with finding substrings returning an array of the non-unique words and positions in text
//
//
import UIKit
let Bigstring = "Why is it so hard to find substrings in Swift3"
let searchStrs : Array<String>? = ["Why", "substrings", "Swift3"]
FindSubString(inputStr: Bigstring, subStrings: searchStrs)
func FindSubString(inputStr : String, subStrings: Array<String>?) -> Array<(String, Int, Int)> {
var resultArray : Array<(String, Int, Int)> = []
for i: Int in 0...(subStrings?.count)!-1 {
if inputStr.contains((subStrings?[i])!) {
let range: Range<String.Index> = inputStr.range(of: subStrings![i])!
let lPos = inputStr.distance(from: inputStr.startIndex, to: range.lowerBound)
let uPos = inputStr.distance(from: inputStr.startIndex, to: range.upperBound)
let element = ((subStrings?[i])! as String, lPos, uPos)
resultArray.append(element)
}
}
for words in resultArray {
print(words)
}
return resultArray
}
Run Code Online (Sandbox Code Playgroud)
返回 ("Why", 0, 3) ("substrings", 26, 36) ("Swift3", 40, 46)
小智 5
我是Swift 3中的新手,但是看起来String
类比的(索引)语法我认为索引就像一个约束到字符串的"指针",而Int可以作为一个独立的对象.使用base + offset语法,然后我们可以从字符串中获取第i个字符,代码如下:
let s = "abcdefghi"
let i = 2
print (s[s.index(s.startIndex, offsetBy:i)])
// print c
Run Code Online (Sandbox Code Playgroud)
对于使用String(range)语法的字符串中的一系列字符(索引),我们可以使用以下代码从第i个字符到第f个字符:
let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg
Run Code Online (Sandbox Code Playgroud)
对于使用String.substring(range)的字符串的子字符串(范围),我们可以使用以下代码获取子字符串:
print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg
Run Code Online (Sandbox Code Playgroud)
笔记:
第i和第f开始于0.
对于第f个,我使用offsetBY:f + 1,因为订阅范围使用.. <(半开放运算符),不包括第f个位置.
当然必须包括验证错误,如无效索引.
斯威夫特 4+
extension String {
func take(_ n: Int) -> String {
guard n >= 0 else {
fatalError("n should never negative")
}
let index = self.index(self.startIndex, offsetBy: min(n, self.count))
return String(self[..<index])
}
}
Run Code Online (Sandbox Code Playgroud)
返回前 n 个字符的子序列,如果字符串较短,则返回整个字符串。(灵感来自:https : //kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html)
例子:
let text = "Hello, World!"
let substring = text.take(5) //Hello
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
273120 次 |
最近记录: |