我一直在更新我的一些旧代码和答案与Swift 3,但当我得到Swift字符串和索引子字符串的事情变得令人困惑。
具体来说,我尝试了以下几点:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
第二行给出了如下错误
String类型的值没有成员substringWithRange
我看到String现在确实有以下方法:
str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)
这些一开始让我很困惑,所以我开始摆弄索引和范围。这是子字符串的后续问题和答案。我在下面添加了一个答案来说明它们是如何使用的。
我是Swift 3的新手,但看看字符串(索引)语法类比,我认为索引就像一个“指针”约束到字符串和Int可以帮助作为一个独立的对象。使用base + offset语法,然后我们可以用下面的代码从string中获得第i个字符:
let s = "abcdefghi"
let i = 2
print (s[s.index(s.startIndex, offsetBy:i)])
// print c
对于字符串中使用string (range)语法的字符范围(索引),我们可以使用下面的代码获得从第i个字符到第f个字符:
let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg
对于字符串中的子字符串(range),使用string。Substring (range),我们可以使用下面的代码获得子字符串:
print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg
注:
第i和f以0开头。
对于f-th,我使用offsetBY: f + 1,因为订阅的范围使用..<(半开操作符),不包括第f个位置。
当然必须包括无效索引等验证错误。
斯威夫特4
在swift 4字符串符合集合。现在应该使用下标,而不是substring。所以如果你只想从“Hello, playground”中删除单词“play”,你可以这样做:
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
有趣的是,这样做会给你一个Substring而不是String。这是快速和有效的,因为Substring与原始字符串共享其存储空间。然而,以这种方式共享内存也很容易导致内存泄漏。
这就是为什么一旦您想要清理原始的String,就应该将结果复制到一个新的String中。你可以使用普通的构造函数:
let newString = String(result)
你可以在[Apple文档].1中找到更多关于新的Substring类的信息
所以,如果你得到一个范围作为nsregularexexpression的结果,你可以使用以下扩展:
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)
}
}
String的特殊性在其他答案中已经讨论过了。解释一下:字符串有一个特定的索引,它不是Int类型,因为字符串元素在一般情况下没有相同的大小。因此,String不符合RandomAccessCollection,访问特定索引意味着遍历集合,这不是O(1)操作。
许多答案都提出了使用范围的变通方法,但它们会导致代码效率低下,因为它们使用的String方法(index(from:), index(:offsetBy:),…)不是O(1)。
要像在数组中一样访问字符串元素,您应该使用array:
let array = Array("Hello, world!")
let letter = array[5]
这是一个权衡,数组创建是一个O(n)操作,但数组访问是O(1)。当你想用String(数组)时,你可以转换回String。
同样的挫折,这应该不难…
我编译了这个从较大文本中获取子字符串位置的示例:
//
// 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
}
返回
("Why" 0,3)
("substrings", 26, 36)
(“Swift3”,40,46)