1
votes

I am trying to retrieve the deleted character from UITextView when user presses delete button on keypad.

When I enter some text in textview for eg:(abc), I am able to retrieve the deleted character by checking the range and location. So no problem for english text

The challenge starts when I have a non english text, for eg "Hindi" language.

Lets say i entered "परक" in textview, and then if I delete one character at a time from right to left, I am able to identify the deleted character as क, र, प respectively.

The real problem start when I have Hindi vowels in the string

For eg: If i have a text as "परी". Then according to Hindi text it contains three characters as प, र, ी. Here ी is a long vowel in Hindi language

When i enter ी in textview, the delegate method is able to identify this text.

However when i press delete button on keyboard to delete ी from word "परी", the range calculation to determine which word is deleted seems to go wrong. I get range value to delete ी as

Range(3..<3) - startIndex : 3 - endIndex : 3

Since startIndex and endIndex are same, I get an empty string.

Following is the code I am using to enter or delete a character in textview

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    if ( range.location == 0 && text == " " )
    {
        return false
    }

    // Its backspace
    if text == ""
    {
        // Set startIndex for Range
        let startIndex = textView.text.startIndex.advancedBy(range.location, limit: textView.text.endIndex)

        // Set new Range
        let newRange = startIndex..<textView.text.startIndex.advancedBy(range.location + range.length, limit: textView.text.endIndex)

        // Get substring
        // Here I get the character that is about to be deleted
        let substring = textView.text[newRange]

        print(substring) //Gives empty string when i delete  ी

        return true
    }

    print(text) // This prints  ी when i enter it in textview  after पर
    return true
}

It would be great if anyone can help me with this. I have checked with Android and it is able to identify ी, when deleted. Awaiting for replies curiously....

Note: Code is written in Swift 2.3

1
Is it the uncode problem? can you try once converting the string to fixed unicode and then comparing the range ?idocode
What is the value of the range received by parameter? I don't know about Hindi characters, but in a Swift Playground, both "परी".characters.count and "पर".characters.count return 2... However, "परी".lengthOfBytes(using: .utf8) is 9 and "पर".lengthOfBytes(using: .utf8) is 6. Seems to be a problem on how you are handling UNICODE strings.Marcos Crispino

1 Answers

2
votes

When I removed the last character of "परी" in a UITextView, I got NSRange(location: 2, length: 1) in the delegate method. It's not empty, as you see, its length is not 0.

The problem is that your code of retrieving the substring is completely wrong.

When an iOS API returns an NSRange for string related operations, its location and length are based on UTF-16, which is the basis of NSString. You should not use those values for characters (String.CharacterView) based index calculation.

Replace these lines of your code:

    // Set startIndex for Range
    let startIndex = textView.text.startIndex.advancedBy(range.location, limit: textView.text.endIndex)

    // Set new Range
    let newRange = startIndex..<textView.text.startIndex.advancedBy(range.location + range.length, limit: textView.text.endIndex)

    // Get substring
    // Here I get the character that is about to be deleted
    let substring = textView.text[newRange]

To:

        //### Get substring
        let substring = (textView.text as NSString).substringWithRange(range)

Your code seems to be written in Swift 2, but in Swift 3, it becomes:

        //### Get substring
        let substring = (textView.text as NSString).substring(with: range)