6

I have implemented a custom keyboard associated with a text field, so when the user presses the delete button, I remove the last character from the string, and manually update the current text field text.

NSRange range = NSMakeRange(currentTextFieldString.length-1, 1);
[currentTextFieldString replaceCharactersInRange:range withString:@""];

So far so good.

Now, the problem is, that the user has the option to enter some special unicode symbols, these are not 1 byte, they can be 2 bytes too, now on pressing the delete button, I have to remove the entire symbol, but if I follow the above approach, the user has to press the delete button twice.

Here, if I do:

NSRange range = NSMakeRange(currentTextFieldString.length-2, 2);
[currentTextFieldString replaceCharactersInRange:range withString:@""];

it works fine, but then, the normal characters, which are just 1 byte, get deleted twice at a time.

How to handle such scenarios?

Thanks in advance.

EDIT:

It is strange, that if I switch to the iPhone keyboard, it handles both cases appropriately. There must be some way to do it, there is something that I am missing, but am not able to figure out what.

Bani Uppal
  • 866
  • 9
  • 17
  • How is your custom keyboard adding characters? – Joe Aug 01 '12 at 13:13
  • My answer on this question might help you http://stackoverflow.com/q/11567049/1487063 – Dustin Aug 01 '12 at 13:14
  • @Joe: whenever the user presses a button, i catch the corresponding character, append it to the current text of the text field, and assign it as the text for the textfield. – Bani Uppal Aug 01 '12 at 13:22
  • @Dustin: Instead of using the method replaceCharactersInRange: withRange: , I used substringToIndex: currentTextFieldString.length-1. It has the same effect. Actually, for special unicodes, it is counting it as 2 indexes. So the user has to press delete key twice to delete such characters. – Bani Uppal Aug 01 '12 at 13:27

3 Answers3

18

Here's the problem. NSStrings are encoded using UTF-16. Many common Unicode glyphs take up only one unichar (a 16 bit unsigned value). However, some glyphs take up two unichars. Even worse, some glyphs can be composed or decomposed, e.g.é might be one Unicode code point or it might be two - an acute accent followed by an e. This makes it quite difficult to do what you want viz delete one "character" because it is really hard to tell how many unichars it takes up.

Fortunately, NSString has a method that helps with this: -rangeOfComposedCharacterSequenceAtIndex:. What you need to do is get the index of the last unichar, run this method on it, and the returned NSRange will tell you where to delete from. It goes something like this (not tested):

NSUInteger lastCharIndex = [myString length] - 1; // I assume string is not empty
NSRange rangeOfLastChar = [myString rangeOfComposedCharacterSequenceAtIndex: lastCharIndex];
myNewString = [myString substringToIndex: rangeOfLastChar.location];
JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • +1 That is exactly what I was looking for. This works great. Some methods are hidden deep inside the docs to find out. – Bani Uppal Aug 01 '12 at 14:37
0

If you can't get this to work by default, then use an if/else block and test if the last character is part of a special character. If it is, use the substring to length-2, otherwise use the substring to length-1.

Dustin
  • 6,783
  • 4
  • 36
  • 53
  • Thanks for the answer! But would that not be an issue, if say the user enters a character from the keyboard, say @/#/$ etc. If I check if the last character is a special character, it would be true in this case, and we would delete 2 characters, where we were to delete one? – Bani Uppal Aug 01 '12 at 13:37
  • I mean, in your if statement check for the specific characters that are giving you problems. Not ones that aren't. – Dustin Aug 01 '12 at 13:39
  • Oh yes, but some that are giving me problems exist in both :) That is the crux of my problem. – Bani Uppal Aug 01 '12 at 13:40
  • Then check the last 2 characters – Dustin Aug 01 '12 at 13:41
  • Oh that is logically correct, thanks for that. But, if I have 2 special characters entered, and the unicode, which 95% is a combination of 2 special characters, i can't decide, again an issue. – Bani Uppal Aug 01 '12 at 13:44
0

I don't know exactly what the problem is there with the special characters byte length.

What i suggest is:

  • Store string length to a param, before adding any new characters
  • If user selects backspace (remove last characters) then remove the string from last length to new length. Means for example last saved string length is 5 and new string length is 7 then remove get a new string with the index from 0 to 4, so it will crop the remaining characters.

This is the other way around to do as i don't know the exact what problem internally.

But i guess logically this solution should work.

Enjoy Coding :)

Mrunal
  • 13,982
  • 6
  • 52
  • 96
  • Oh Yes, this should work I guess. Thanks for the answer, but I am still confused on how to solve it with a more methodological approach. I have tried all sorts of things, like converting it into NSData, then removing the bytes, to see what actually happens, but to no avail :( – Bani Uppal Aug 01 '12 at 13:39