Как разбить и перестроить строку с помощью NSRange в Swift - PullRequest
1 голос
/ 03 марта 2020

Я использую 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? или есть лучший способ, который я пропустил?

...