我正尝试使用我在下面键入的代码将段落拆分为组件数组。我在使用范围元素时遇到了麻烦。我的问题是,如果用户多次键入一个字符串,它将返回第一次的范围,而不是我想要的范围。
示例:
第1段:香蕉
第2段:苹果
第3段:香蕉
第1款和第3款都将具有第1款的范围。解决此问题的更聪明的方法是什么?
lazy var models: [ParagraphModel] = []
struct ParagraphModel {
let text: String
let range: Range<String.Index>
}
func getParagraphs(){
let components = textView.text.components(separatedBy: "\n")
let models = components.compactMap { component -> ParagraphModel? in
if let range = textView.text.range(of: component) {
return ParagraphModel(text: component, range: range)
}
return nil
}
self.models = models
}
@Rob中的更新代码:
func getParagraphModel() {
guard let text = noteContents.text else { return }
var currentModels: [ParagraphModel] = []
text.enumerateSubstrings(in: text.startIndex..., options: .byParagraphs) { substring, range, _, stop in
if let substring = substring, !substring.isEmpty,
let textRange = self.noteContents.text.range(of: substring)
{
currentModels.append(ParagraphModel(text: substring, range: textRange))
}
}
self.models = currentModels
}
键入示例文本时,控制台的打印输出为:
[Project.ViewController.ParagraphModel(text: "Banana", range: Range(Swift.String.Index(_rawBits: 0)..<Swift.String.Index(_rawBits: 393216))), Project.ViewController.ParagraphModel(text: "Apple", range: Range(Swift.String.Index(_rawBits: 458752)..<Swift.String.Index(_rawBits: 786432))), Project.ViewController.ParagraphModel(text: "Banana", range: Range(Swift.String.Index(_rawBits: 0)..<Swift.String.Index(_rawBits: 393216)))]
答案 0 :(得分:1)
您的代码段中的问题是,您总是要查找目标字符串的第一个匹配项。因此,当搜索第三段“香蕉”时,它将找到该字符串的第一个匹配项。
我建议text.enumerateSubstrings(in:options:_:)
获取text
内段落的范围。这将枚举子字符串及其各自的范围,从而避免了您自己搜索文本,避免了如果同一字符串多次出现可能引起的问题。
因此:
func getParagraphs() {
guard let textView = textView, let text = textView.text else { return }
models = []
text.enumerateSubstrings(in: text.startIndex..., options: .byParagraphs) { substring, range, _, _ in
guard let substring = substring, !substring.isEmpty else {
return
}
self.models.append(ParagraphModel(text: substring, range: range))
}
}
产生:
[
MyApp.ParagraphModel(text: "Paragraph 1: Banana", range: Range(Swift.String.Index(_rawBits: 0)..<Swift.String.Index(_rawBits: 1245184))),
MyApp.ParagraphModel(text: "Paragraph 2: Apple", range: Range(Swift.String.Index(_rawBits: 1376256)..<Swift.String.Index(_rawBits: 2555904))),
MyApp.ParagraphModel(text: "Paragraph 3: Banana", range: Range(Swift.String.Index(_rawBits: 2686976)..<Swift.String.Index(_rawBits: 3932160)))
]
或者,如果range
中的ParagraphModel
是UITextRange
,则可以:
func getParagraphs() {
guard let textView = textView, let text = textView.text else { return }
models = []
text.enumerateSubstrings(in: text.startIndex..., options: .byParagraphs) { substring, range, _, stop in
let nsRange = NSRange(range, in: text)
if let substring = substring,
!substring.isEmpty,
let start = textView.position(from: textView.beginningOfDocument, offset: nsRange.location),
let end = textView.position(from: start, offset: nsRange.length),
let textRange = self.textView.textRange(from: start, to: end)
{
self.models.append(ParagraphModel(text: substring, range: textRange))
}
}
}
制作:
[
MyApp.ParagraphModel(text: "Paragraph 1: Banana", range: <_UITextKitTextRange: 0x6000037983e0> (0, 19)F),
MyApp.ParagraphModel(text: "Paragraph 2: Apple", range: <_UITextKitTextRange: 0x600003798260> (21, 18)F),
MyApp.ParagraphModel(text: "Paragraph 3: Banana", range: <_UITextKitTextRange: 0x600003799f20> (41, 19)F)
]