i有一个nstextview显示log(价值15 mb的文本(。日志中将有时间戳。示例片段:
2018-04-22 07:54:49 <Homebound> [tests > ... Ending
2018-04-22 07:54:49 <Homebound> [tests > ... Starting
launchctl load /System/Library/
2018-04-22 07:54:50 (null)
我有一个带时间戳记的下拉菜单。时间戳是具有此格式的字符串:
2018-04-22 07:54:49
目前,我可以从下拉菜单中选择一个时间戳,并在NstextView中找到时间戳,然后滚动到时间戳所在。这是代码:
let haystack = myTextBox.string
var needle = failuresArray[selectedIndex - 1][3]
needle.removeLast(2)
// (needle would like like: 2018-04-22 07:54)
if let needleRange = haystack.range(of: needle) {
myTextBox.scrollRangeToVisible(NSRange(needleRange, in: haystack))
}
我遇到的问题是,确切的时间戳可能不在NstextView中显示的日志中。如何在NstextView中找到最接近的时间戳并滚动到它?
一种方法是在您的时间戳上构建某种索引:
- 创建两个变量
-
var index: [String: [Range<String.Index>]]
-
var timestamps: [String]
-
- 当您获得文本时,每个时间戳一次迭代一次,每个时间戳一次:
- 计算相应的范围
- 将条目添加到
index
将其附加到timestamps
- 查询时间戳时,请在
timestamps
中查找它:- 如果存在返回第一个范围
- 如果没有,请在
timestamps
上使用二进制搜索获取最接近的搜索并在index
中查询其范围
您可能想作为背景任务执行此索引。
我会以几个步骤操作。
- 用正则表达式隔离时间戳。
- 将时间戳转换为日期(使用日期格式(,然后将日期转换为TimeInterval,您可以从中提取文本字段中的时间参考并获取绝对值。
代码将是:
let str = <your string>
var closestRange = NSRange(location: NSNotFound, length: 0)
var smallestDelta : TimeInterval = TimeInterval.infinity
let refTimeInterval = <Date from the text field>.timeIntervalSinceReferenceDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
if let regex = try? NSRegularExpression(pattern: "\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}", options: []) {
for match in regex.matches(in: str, options: [], range: NSRange(location: 0, length: (str as NSString).length)) {
let range = match.range(at: 0)
let substring = (str as NSString).substring(with: range)
if let date = dateFormatter.date(from: substring) {
let delta = abs(date.timeIntervalSinceReferenceDate - refTimeInterval)
if delta < smallestDelta {
closestRange = range
smallestDelta = delta
}
}
}
}
print(closestRange)
正则表达式是一个漫长的话题,但是很容易找到有关它们的信息,例如:https://www.raywenderlich.com/86205/nsregularexpression-swift-swift-tutorial
当然,某种形式的索引会更好,但是我想问题的主要部分是将日期隔离并将其转换为适当的日期。