Я использую https://github.com/GitHawkApp/StyledTextKit для его возможностей фонового рендеринга. Теперь я разбираю строки перед рендерингом, чтобы проверить наличие текстового содержимого, например: регулярное выражение.
Вот как я анализирую свой текст:
private func parseText(_ text: String) -> [NSTextCheckingResult] {
let attributedString = NSAttributedString(string: text)
let range = NSRange(location: 0, length: text.count)
var matches = [NSTextCheckingResult]()
// Get matches of all .custom DetectorType and add it to matches array
let regexs = MarkdownAttribute.enabledDetectors
.filter { $0.isCustom }
.map { parseForMatches(with: $0, in: attributedString, for: range) }
.joined()
matches.append(contentsOf: regexs)
// Get all Checking Types of detectors, except for .custom because they contain their own regex
let detectorCheckingTypes = MarkdownAttribute.enabledDetectors
.filter { !$0.isCustom }
.reduce(0) { $0 | $1.textCheckingType.rawValue }
if detectorCheckingTypes > 0, let detector = try? NSDataDetector(types: detectorCheckingTypes) {
let detectorMatches = detector.matches(in: text, options: [], range: range)
matches.append(contentsOf: detectorMatches)
}
guard MarkdownAttribute.enabledDetectors.contains(.url) else {
return matches
}
// Enumerate NSAttributedString NSLinks and append ranges
var results: [NSTextCheckingResult] = matches
attributedString.enumerateAttribute(NSAttributedString.Key.link, in: range, options: []) { value, range, _ in
guard let url = value as? URL else { return }
let result = NSTextCheckingResult.linkCheckingResult(range: range, url: url)
results.append(result)
}
return results
}
public enum DetectorType: Hashable {
case address
case date
case phoneNumber
case url
case transitInformation
case custom(NSRegularExpression)
// swiftlint:disable force_try
public static var hashtag = DetectorType.custom(try! NSRegularExpression(pattern: "#[a-zA-Z0-9]{4,}", options: []))
public static var mention = DetectorType.custom(try! NSRegularExpression(pattern: "@[a-zA-Z0-9]{4,}", options: []))
// swiftlint:enable force_try
internal var textCheckingType: NSTextCheckingResult.CheckingType {
switch self {
case .address: return .address
case .date: return .date
case .phoneNumber: return .phoneNumber
case .url: return .link
case .transitInformation: return .transitInformation
case .custom: return .regularExpression
}
}
/// Simply check if the detector type is a .custom
public var isCustom: Bool {
switch self {
case .custom: return true
default: return false
}
}
///The hashValue of the `DetectorType` so we can conform to `Hashable` and be sorted.
public func hash(into: inout Hasher) {
into.combine(toInt())
}
/// Return an 'Int' value for each `DetectorType` type so `DetectorType` can conform to `Hashable`
private func toInt() -> Int {
switch self {
case .address: return 0
case .date: return 1
case .phoneNumber: return 2
case .url: return 3
case .transitInformation: return 4
case .custom(let regex): return regex.hashValue
}
}
}
private func parseForMatches(with detector: MarkdownAttribute.DetectorType, in text: NSAttributedString, for range: NSRange) -> [NSTextCheckingResult] {
switch detector {
case .custom(let regex):
return regex.matches(in: text.string, options: [], range: range)
default:
fatalError("You must pass a .custom DetectorType")
}
}
StyledTextKit
имеет функции для легкого построения NSAttributedString
. Добавление строки с чертами. или добавление черт в строку.
, так что теперь у меня есть массив [NSTextCheckingResult]
. Как перестроить, используя диапазон, предоставленный NSTextCheckingResult
? или есть лучший способ, который я пропустил?