字符串子字符串在Swift中是如何工作的
我一直在用Swift 3更新我的一些旧代码和答案,但是当我使用Swift字符串和子字符串进行索引时,事情变得很混乱 具体而言,我尝试了以下几点:字符串子字符串在Swift中是如何工作的,swift,string,range,substring,Swift,String,Range,Substring,我一直在用Swift 3更新我的一些旧代码和答案,但是当我使用Swift字符串和子字符串进行索引时,事情变得很混乱 具体而言,我尝试了以下几点: let str = "Hello, playground" let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) let prefix = str.substringWithRange(prefixRange) String(t3) String(t4)
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
String(t3)
String(t4)
一开始我真的很困惑,所以我开始到处玩。这是子字符串的后续问题和答案。我在下面添加了一个答案来说明它们是如何使用的。
以下所有示例都使用
var str = "Hello, playground"
斯威夫特4
弦乐在《斯威夫特4》中得到了相当大的改进。当您现在从字符串中获得一些子字符串时,您会得到一个子字符串
而不是字符串
。为什么会这样?字符串是Swift中的值类型。这意味着,如果您使用一个字符串来创建一个新字符串,则必须将其复制过来。这有利于稳定性(没有人会在你不知情的情况下改变它),但不利于效率
另一方面,子字符串是对其来源的原始字符串的引用。下面是一张来自于的图片,说明了这一点
无需复制,因此使用效率更高。但是,假设您从一个百万字符的字符串中得到了一个十个字符的子字符串。因为子字符串引用字符串,所以只要子字符串存在,系统就必须保持整个字符串。因此,无论何时操作完子字符串,都要将其转换为字符串
let myString = String(mySubstring)
这将只复制子字符串,并且可以复制保存旧字符串的内存。子字符串(作为一种类型)的寿命很短
Swift 4的另一大改进是字符串是集合(同样)。这意味着您可以对集合执行任何操作,也可以对字符串执行任何操作(使用下标、迭代字符、过滤器等)
以下示例演示如何在Swift中获取子字符串
获取子字符串
您可以使用下标或许多其他方法(例如,前缀
,后缀
,拆分
)从字符串中获取子字符串。不过,您仍然需要使用String.Index
,而不是范围的Int
索引。(看看你是否需要帮助。)
字符串的开头
您可以使用下标(注意Swift 4单边范围):
甚至更简单:
let mySubstring = str.prefix(5) // Hello
let mySubstring = str.suffix(10) // playground
弦外之音
使用下标:
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground
或后缀
:
let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground
甚至更简单:
let mySubstring = str.prefix(5) // Hello
let mySubstring = str.suffix(10) // playground
注意,当使用后缀(from:index)
时,我必须使用-10
从末尾倒数。当只使用后缀(x)时,这是不必要的,它只接受字符串的最后一个x
字符
let myString = String(mySubstring)
字符串中的范围
同样,我们在这里只使用下标
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
使用Int
索引扩展名?
在阅读了空速和奥勒·贝格曼的文章之后,我很犹豫是否使用基于Int
的索引扩展。尽管在Swift 4中,字符串是集合,但Swift团队故意没有使用Int
索引。它仍然是String.Index
。这与由不同数量的Unicode代码点组成的Swift字符有关。必须为每个字符串唯一地计算实际索引
我不得不说,我希望Swift团队将来能找到一种方法来提取
String.Index
。但在他们之前,我选择使用他们的API。它帮助我记住字符串操作不仅仅是简单的Int
索引查找 我对斯威夫特的字符串访问模型非常失望:所有东西都必须是索引。我只想使用Int
访问字符串的第I个字符,而不是笨拙的索引和前进(每一个主要版本都会发生变化)。因此,我对字符串进行了扩展:
extension String {
func index(from: Int) -> Index {
return self.index(startIndex, offsetBy: from)
}
func substring(from: Int) -> String {
let fromIndex = index(from: from)
return String(self[fromIndex...])
}
func substring(to: Int) -> String {
let toIndex = index(from: to)
return String(self[..<toIndex])
}
func substring(with r: Range<Int>) -> String {
let startIndex = index(from: r.lowerBound)
let endIndex = index(from: r.upperBound)
return String(self[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
扩展字符串{
func索引(from:Int)->index{
返回自索引(起始索引,抵销人:起始)
}
func子字符串(from:Int)->字符串{
let fromIndex=索引(from:from)
返回字符串(self[fromIndex…])
}
func子字符串(to:Int)->字符串{
让toIndex=索引(从:到)
返回字符串(self[…字符串{
让startIndex=索引(起始:r.lowerBound)
让endIndex=index(from:r.upperBound)
返回字符串(self[startIndex..我也有同样的最初反应。我也对语法和对象在每个主要版本中的变化如此剧烈感到沮丧
然而,我从经验中认识到,我总是会最终承受与“变化”抗争的后果,就像处理多字节字符一样,如果你面对的是全球受众,这是不可避免的
因此,我决定承认并尊重苹果工程师所做的努力,并在他们提出这种“可怕”的方法时,通过理解他们的心态来尽我的一份力量
与其创建只是让您的生活更轻松的变通方法的扩展(我不是说它们是错误的或昂贵的),为什么不弄清楚字符串现在是如何工作的呢
例如,我有一个在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)
在放弃尝试使用相同的方法(例如使用子字符串)后,我终于理解了将字符串视为双向集合的概念,我最终得到了相同代码的这个版本:
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))
我希望这有助于…同样的沮丧,这不应该那么难
我编译了这个从较大文本中获取子字符串位置的示例:
//
// 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
}
//
//尝试查找返回文本中非唯一单词和位置数组的子字符串
//
//
导入UIKit
let Bigstring=“为什么在Swift3中很难找到子字符串”
让searchStrs:Array?=[“为什么”,“子字符串”,“Swift3”]
FindSubString(inputStr:Bigstring,SubString:searchStrs)
func FindSubString(inputStr:String,substring:Array?->Array{
var resultArray:Array=[]
对于i:0中的Int…(子字符串?.count)!-1{
如果inputStr.包含((子字符串?[i])!)
let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg
print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg
extension String {
func substring(location: Int, length: Int) -> String? {
guard characters.count >= location + length else { return nil }
let start = index(startIndex, offsetBy: location)
let end = index(startIndex, offsetBy: location + length)
return substring(with: start..<end)
}
}
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
}
}
extension String {
subscript(_ range: CountableRange<Int>) -> String {
let start = index(startIndex, offsetBy: max(0, range.lowerBound))
let end = index(start, offsetBy: min(self.count - range.lowerBound,
range.upperBound - range.lowerBound))
return String(self[start..<end])
}
subscript(_ range: CountablePartialRangeFrom<Int>) -> String {
let start = index(startIndex, offsetBy: max(0, range.lowerBound))
return String(self[start...])
}
}
let s = "hello"
s[0..<3] // "hel"
s[3...] // "lo"
let s = "Swift 4
In swift 4 String
conforms to Collection
. Instead of substring
, we should now use a subscript.
So if you want to cut out only the word "play"
from "Hello, playground"
, you could do it like this:
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
let newString = String(result)
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)
}
}
extension String {
subscript(_ i: Int) -> String {
let idx1 = index(startIndex, offsetBy: i)
let idx2 = index(idx1, offsetBy: 1)
return String(self[idx1..<idx2])
}
}
let s = "hello"
s[0] // h
s[1] // e
s[2] // l
s[3] // l
s[4] // o
let greeting = "Hi there! It's nice to meet you! Heres a more generic implementation:
This technique still uses index
to keep with Swift's standards, and imply a full Character.
extension String
{
func subString <R> (_ range: R) -> String? where R : RangeExpression, String.Index == R.Bound
{
return String(self[range])
}
func index(at: Int) -> Index
{
return self.index(self.startIndex, offsetBy: at)
}
}
let item = "Fred looks funny"
item.subString(item.index(at: 2)...) // "ed looks funny"
var str = "abc\u{1A}12345sdf"
let range1: Range<String.Index> = str.range(of: "\u{1A}")!
let index1: Int = str.distance(from: str.startIndex, to: range1.lowerBound)
let start = str.index(str.startIndex, offsetBy: index1)
let end = str.index(str.endIndex, offsetBy: -0)
let result = str[start..<end] // The result is of type Substring
let firstStr = str[str.startIndex..<range1.lowerBound]
var fString = String()
for (n,c) in str.enumerated(){
*if c == "\u{1A}" {
print(fString);
let lString = str.dropFirst(n + 1)
print(lString)
break
}
fString += String(c)
}*
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
String(t3)
String(t4)
let mid = t.index(t.endIndex, offsetBy:-5)
let firstHalf = t[..<mid]
let secondHalf = t[mid...]
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])
}
}
let text = "Hello, World!"
let substring = text.take(5) //Hello
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])
}
}
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
var str = "VEGANISM"
print (str[str.index(str.startIndex, offsetBy:2)..<str.index(str.endIndex, offsetBy: -1)] )
//Output-> GANIS
var str = "VEGANISM"
print (str[str.index(str.startIndex, offsetBy:0)..<str.index(str.endIndex, offsetBy: 0)] )
//Output-> VEGANISM