// // RichTextParser.swift // RichTextView // // Created by Ahmed Elkady on 2018-11-08. // Copyright © 2018 Top Hat. All rights reserved. // import Down import UIKit class RichTextParser { // MARK: - Constants enum ParserConstants { static let mathTagName = "math" static let interactiveElementTagName = "interactive-element" static let highlightedElementTagName = "highlighted-element" static let latexRegex = "\\[\(ParserConstants.mathTagName)\\](.*?)\\[\\/\(ParserConstants.mathTagName)\\]" static let latexRegexCaptureGroupIndex = 0 static let interactiveElementRegex = """ \\[\(ParserConstants.interactiveElementTagName)\\sid=.+?\\].*?\\[\\/\(ParserConstants.interactiveElementTagName)\\] """ static let highlightedElementRegex = """ \\[\(ParserConstants.highlightedElementTagName)\\sid=.+?\\].*?\\[\\/\(ParserConstants.highlightedElementTagName)\\] """ private static let tAPlaceholderPrefix = "{RichTextView-TextAttachmentPosition" private static let tAPlaceholderSuffix = "}" static let textAttachmentPlaceholderAssigner = "=" static let textAttachmentPlaceholderRegex = "\\\(ParserConstants.tAPlaceholderPrefix)\(ParserConstants.textAttachmentPlaceholderAssigner)[0-9]+?\\\(ParserConstants.tAPlaceholderSuffix)" static let textAttachmentPlaceholder = "\(ParserConstants.tAPlaceholderPrefix)\(ParserConstants.textAttachmentPlaceholderAssigner)%d\(ParserConstants.tAPlaceholderSuffix)" typealias RichTextWithErrors = (output: NSAttributedString, errors: [ParsingError]?) static let bulletString = "•" static let listOpeningHTMLString = "
", with: "").replacingOccurrences(of: "
", with: "") } private func unescapeHTML(from input: String) -> String { return input.replacingOccurrences(of: "&", with: "&") .replacingOccurrences(of: "<", with: "<") .replacingOccurrences(of: ">", with: ">") .replacingOccurrences(of: """, with: "\"") .replacingOccurrences(of: "'", with: "'") .replacingOccurrences(of: " ", with: " ") } // MARK: - String Helpers private func split(mutableAttributedString: NSMutableAttributedString, onPositions positions: [String.Index]) -> [NSAttributedString] { let splitStrings = mutableAttributedString.string.split(atPositions: positions) var output = [NSAttributedString]() for string in splitStrings { let range = (mutableAttributedString.string as NSString).range(of: string) let attributedString = mutableAttributedString.attributedSubstring(from: range) output.append(attributedString) } return output } private func extractPositions(fromRanges ranges: [Range