Разделить параграфы и сохранить диапазоны в UITextView - PullRequest
1 голос
/ 29 июня 2019

Я пытаюсь разбить абзацы на массив компонентов, используя код, который я напечатал ниже. У меня проблемы с элементом Ranges. Моя проблема в том, что если пользователь вводит строку несколько раз, он возвращает первый диапазон, а не тот, который я хочу.

Пример:
Пункт 1: банан
Пункт 2: Apple
Пункт 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)))]

1 Ответ

1 голос
/ 29 июня 2019

Проблема в вашем фрагменте кода заключается в том, что вы всегда будете находить первое вхождение целевой строки.Поэтому, когда он ищет третий абзац «Банан», он находит первое вхождение этой строки.

Я бы предложил 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)
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...