Выделение слов с помощью TextKit для выбора неправильного вхождения повторяющихся слов

Я на самом деле разрабатываю приложение Корана, в котором я использую TextKit, чтобы выделить стихи и изменить их цвет. Все идет отлично, но у меня есть небольшая проблема со словами, которые появляются несколько раз. Прежде всего, мой код:

    import UIKit

class ViewController: UIViewController {

    let attributedBackgroundColor = [ NSBackgroundColorAttributeName: UIColor.lightGray ]
    var myVerses = ["بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ","الْحَمْدُ لِلَّهِ رَبِّ الْعَالَمِينَ","الرَّحْمَنِ الرَّحِيمِ","مَالِكِ يَوْمِ الدِّينِ","إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ","اهدِنَا الصِّرَاطَ الْمُسْتَقِيمَ","صِرَاطَ الَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ الْمَغْضُوبِ عَلَيْهِمْ وَلاَ الضَّالِّينَ"]

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

       let string = NSMutableAttributedString(string: "Vide initialement")
        string.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: CGFloat(25.0)), range: NSRange(location: 0, length: string.length))
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: string.length))

        textView.attributedText = string
        let singleTap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapRecognized))
        singleTap.numberOfTapsRequired = 1
        textView.addGestureRecognizer(singleTap)
        textView.isEditable = false
        textView.isSelectable = false

        var str = ""

// Ajouter numérotation aux verses - Add numerotation to verses.
        for i in 0..<myVerses.count {
            if i > 0 {
                str += "("+"\(i)"+")"
            }
            str += String(myVerses[i])
        }
        print(str)
        textView.text = str + "("+"\(myVerses.count)"+")"
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }


   // Sélection des verses - Select Verses
    func tapRecognized(_ recognizer: UITapGestureRecognizer) {
        if recognizer.state == .recognized {
            let point = recognizer.location(in: recognizer.view)
            let detectedText = self.getWordAtPosition(pos: point, in: textView)
            if (detectedText != "") {
                print("detectedText  == \(detectedText)")
                let string = NSMutableAttributedString(string: self.textView.text)
                let verses = self.textView.text.components(separatedBy: ")")



                if let detectedRange = textView.text.range(of: detectedText) {
                    let startPosOfSubstring = textView.text.distance(from: textView.text.startIndex, to: detectedRange.lowerBound)
                    let detectedLength = detectedText.characters.count
               let rangeOfSub = (startPosOfSubstring,detectedLength)
               print("-- rangeofSub == " ,rangeOfSub)
                    let rangeOfSubstring = NSRange(location: startPosOfSubstring, length: detectedLength)


                    for verse: String in verses {
                        if let detectedVerse = textView.text.range(of: verse) {
                            let startPosOfVerse = textView.text.distance(from: textView.text.startIndex, to: detectedVerse.lowerBound)
                            let detectedLengthOfVerse = verse.characters.count

                            let tupleVerse = (startPosOfVerse,detectedLengthOfVerse)
                            print("++ rangeofVerse == " ,tupleVerse)
                            let rangeOfVerse = NSRange(location: startPosOfVerse, length: detectedLengthOfVerse)
                            print(verse)


                            let range = (self.textView.text as NSString).range(of: verse)
                            let contained = NSLocationInRange(rangeOfSubstring.location, rangeOfVerse)
                            if (contained) {
                                print ("************************************")
                            print("contained is :" ,contained)
                                print ("************************************")

                                string.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: range)
                                string.addAttribute(NSBackgroundColorAttributeName, value: UIColor.darkGray, range: range)
                                string.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: CGFloat(25.0)), range: NSRange(location: 0, length: string.length))
                                let paragraphStyle = NSMutableParagraphStyle()
                                paragraphStyle.alignment = .center
                                string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: string.length))

                            }
                            print ("--------------------------------------------")

                        }

                    }
                    self.textView.attributedText = string
                } else {
                    print("detectedText is empty")
                }
            }
        }
    }



    func getWordAtPosition( pos: CGPoint, in textview: UITextView) -> String {
        //Eleminer le balancement du scroll - eliminate scroll offset
     //   var pos = pos
    //    pos.y += tv.contentOffset.y
        //Position du text tapé au point - get location in text from textposition at point
        let tapPos = textview.closestPosition(to: pos)
        //Avoir le mot tapé dans la position du point - fetch the word at this position (or nil, if not available)
        if let wr = textview.tokenizer.rangeEnclosingPosition(tapPos!, with: .word, inDirection: UITextLayoutDirection.right.rawValue) {
            print(pos)
            return textview.text(in: wr)!
        }else{
            return ""
        }

    }
}

Когда я запускаю свое приложение на симуляторе, я выбираю стих, и он идет отлично.

Нормальное использование:

Нормальное использование

Проблема со словами, которые появляются более одного раза. Например, для слова "الرحمن", которое встречается дважды, независимо от того, выберу я первый или второй, выделенный стих всегда будет первым.

проблема

Что я делаю неправильно? Заранее спасибо.

1 ответ

Как я понимаю ваш вопрос, вы хотите выделить весь стих, когда пользователь выбирает конкретное слово в этом стихе.

Проблема в вашей логике состоит в том, что вы определяете слово, которое выбрал пользователь, но это слово не обязательно уникально, поэтому при поиске этого слова (с textView.text.range(of: detectedText)), вы получите первый результат, который может быть, а может и не быть тем, который фактически выбрал пользователь.

Одним из возможных решений, если токенизатор правильно понимает ваш текст, является использование другого TextGranularity при определении выбора пользователя. Вместо:

textview.tokenizer.rangeEnclosingPosition(tapPos!, with: .word, inDirection: UITextLayoutDirection.right.rawValue)

Вы можете попробовать:

textview.tokenizer.rangeEnclosingPosition(tapPos!, with: .sentence, inDirection: UITextLayoutDirection.right.rawValue)
Другие вопросы по тегам