Character code in NSString to unicode character - ios

I have an NSString with a charactercode like this: 0x1F514.
I want to take this NSString and add it to another NSString, but not with the literal value of it, but the icon hidden behind it. In this case an emoticon of a bell.
How can I easily convert this NSString to show the emoticon instead of the character code?

Something like this would do:
NSString *c = #"0x1F514";
unsigned intVal;
NSScanner *scanner = [NSScanner scannerWithString:c];
[scanner scanHexInt:&intVal];
NSString *str = nil;
if (intVal > 0xFFFF) {
unsigned remainder = intVal - 0x10000;
unsigned topTenBits = (remainder >> 10) & 0x3FF;
unsigned botTenBits = (remainder >> 0) & 0x3FF;
unichar hi = topTenBits + 0xD800;
unichar lo = botTenBits + 0xDC00;
unichar unicodeChars[2] = {hi, lo};
str = [NSString stringWithCharacters:unicodeChars length:2];
} else {
unichar lo = (unichar)(intVal & 0xFFFF);
str = [NSString stringWithCharacters:&lo length:1];
}
NSLog(#"str = %#", str);
The reason simply #"\u1f514" doesn't work is because those \u values cannot be outside the BMP, i.e. >0xFFFF, i.e. >16-bit.
So, what my code does is check for that scenario and does the relevant surrogate pair magic to make the right string.
Hopefully that is actually what you want and makes sense!

If your NSString contains this "bell" character, then it does. You just append strings the usual way, like with stringByAppendingString.
The drawing of a bell instead of something denoting an unknown character is a completely separate issue. Your best bet is to ensure you're not using CoreText for drawing this, as it's been reported elsewhere, and I've seen it myself at work, that various non-standard characters may not work when printed that way. They do work, however, when printed with UIKit (that should be standard UI components, UIKitAdditions, and so on).
If using CoreText, you might get a bit lucky if you disable some text properties for the string with this special character, or choose appropriate font (but I won't help you here; we decided to leave the issue as Won't fix).
Having said that, the last time I was dealing with those was in pre-iOS 6 days...
Summary: your problem is not appending strings, but how you draw them.

Related

In iOS, how can I get the address of self as a string?

If it matters I need this particularly when self is a UIView subclass. By way of example to clarify my question, the following stmt:
NSLog(#"self: %#", self);
gives the following output:
<RCLDataView: 0x10971a0b0; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; opaque = NO; layer = (null)>
I want just that address (0x10971a0b0) without the rest of the text. I suppose I can (somehow) capture that full string and (somehow) extract the address with NSString methods. But that seems really ugly. There is probably a way to get the address directly, since NSLog can get it.
NSString *addressString = [NSString stringWithFormat:#"%p", yourString];
unsigned long long address = 0;
NSScanner *scanner = [NSScanner scannerWithString:addressString];
[scanner scanHexLongLong:&address];
NSLog(#"%llx", address); //Prints the address
The first line gets the pointer address and puts it into an NSString.
The next line instantiates an unsigned long long to hold the hex value of the pointer. The pointer address representation is 64 bits I think so we need a 64 bit value to hold it. I know an int is not large enough but a long long works. Alternatively you could use a uint64_t depending on your architecture. The next two lines are to extract the hex value and store it in our long long. The NSScanner method is the only way I know to get a hex value from an NSString so I just used that. The last line of course is to print the value to make sure it's correct. You can check if it's correct by also printing the addressString.

arc4random_uniform output issue

in iOS Objetive-C I am trying to get the number typed by the user in a text field to set the upper bounder of a random number generation function in C.
- (IBAction)pushTheButton2:(id)sender {
u_int32_t upperBound = (u_int32_t) textField3.text;
textField4.text = [NSString stringWithFormat:#"%d", arc4random_uniform(upperBound)];
}
The output is a giant number that makes no sense. To test if function works, if I hardcode the actual upper bound in the arc4random_uniform function, such as arc4random_uniform(5), then it works!
I figured this could be some kind of literal conversion, so I tried to make this work with u_int32_t but still not outputting the right range.
Can someone help? Thanks
You are currently taking the memory reference pointer of the text and using that as the upper bound.
Try doing something like this instead...
NSInteger upperBound = [textfield.text intValue];
This will convert the string into an int that you can then use in the arc random function.
To parse string to integer you should do:
NSInteger upperBound = [textfield.text integerValue];

Text string with EMOJI causing issues with NSRange

I am using TTTAttributedLabel to apply formatting to text, however it seems to crash because I am trying to apply formatting to a range which includes emoji. Example:
NSString *text = #"#user1234 🍺🍺 #hashtag"; // text.length reported as 22 by NSLog as each emoji is 2 chars in length
cell.textLabel.text = text;
int length = 8;
int start = 13;
NSRange *range = NSMakeRange(start, length);
if (!NSEqualRanges(range, NSMakeRange(NSNotFound, 0))) {
// apply formatting to TTTAttributedLabel
[cell.textLabel addLinkToURL:[NSURL URLWithString:[NSString stringWithFormat:#"someaction://hashtag/%#", [cell.textLabel.text substringWithRange:range]]] withRange:range];
}
Note: I am passed the NSRange values from an API, as well as the text string.
In the above I am attempting to apply formatting to #hashtag. Normally this works fine, but because I have emoji involved in the string, I believe the range identified is attempting to format the emoji, as they are actually UTF values, which in TTTAttributedLabel causes a crash (it actually hangs with no crash, but...)
Strangely, it works fine if there is 1 emoji, but breaks if there are 2.
Can anyone help me figure out what to do here?
The problem is that any Unicode character in your string with a Unicode value of \U10000 or higher will appears as two characters in NSString.
Since you want to format the hashtag, you should use more dynamic ways to obtain the start and length values. Use NSString rangeOfString to find the location of the # character. Use that results and the string's length to get the needed length.
NSString *text = #"#user1234 🍺🍺 #hashtag"; // text.length reported as 22 by NSLog as each emoji is 2 chars in length
cell.textLabel.text = text;
NSUInteger start = [text rangeOfString:#"#"];
if (start != NSNotFound) {
NSUInteger length = text.length - start;
NSRange *range = NSMakeRange(start, length);
// apply formatting to TTTAttributedLabel
[cell.textLabel addLinkToURL:[NSURL URLWithString:[NSString stringWithFormat:#"someaction://hashtag/%#", [cell.textLabel.text substringWithRange:range]]] withRange:range];
}
I assume this is from the Twitter API, and you are trying to use the entities dictionary they return. I have just been writing code to support handling those ranges along with NSString's version of the range of a string.
My approach was to "fix" the entities dictionary that Twitter return to cope with the extra characters. I can't share code, for various reasons, but this is what I did:
Make a deep mutable copy of the entities dictionary.
Loop through the entire range of the string, unichar by unichar, doing this:
Check if the unichar is in the surrogate pair range (0xd800 -> 0xdfff).
If it is a surrogate pair codepoint, then go through all the entries in the entities dictionary and shift the indices by 1 if they are greater than the current location in the string (in terms of unichars). Then increment the loop counter by 1 to skip the partner of this surrogate pair as it's been handled now.
If it's not a surrogate pair, do nothing.
Loop through all entities and check that none of them overrun the end of the string. They shouldn't, but just incase. I found some cases where Twitter returned duff data.
I hope that helps! I also hope that one day I can open source this code as I think it would be incredibly useful!

Which characters does NSLineBreakByWordWrapping break on?

Short version
From the docs:
NSLineBreakByWordWrapping
Wrapping occurs at word boundaries, unless the word itself doesn’t fit on a single line.
What is the set of all word boundary characters?
Longer version
I have a set of UILabels, which contain text, sometimes including URLs. I need to know the exact location (frame, not range) of the URLs so that I can make them tappable. My math mostly works, but I had to build in a test for certain characters:
// This code only reached if the URL is longer than the available width
NSString *theText = // A string containing an HTTP/HTTPS URL
NSCharacterSet *breakChars = [NSCharacterSet characterSetWithCharactersInString:#"?-"];
NSString *charsInRemaininsSpace = // NSString with remaining text on this line
NSUInteger breakIndex = NSNotFound;
if (charsInRemaininsSpace)
breakIndex = [charsInRemaininsSpace rangeOfCharacterFromSet:breakChars
options:NSBackwardsSearch].location;
if (breakIndex != NSNotFound && breakIndex != theText.length-1) {
// There is a breakable char in the middle, so draw a URL through that, then break
// ...
} else {
// There is no breakable char (or it's at the end), so start this word on a new line
// ...
}
The characters in my NSCharacterSet are just ? and -, which I discovered NSLineBreakByWordWrapping breaks on. It does not break on some other characters I see in URLs like % and =. Is there a complete list of characters I should be breaking on?
I recommend using "not alphanumeric" as your test.
[[NSCharacterSet alphanumerCharacterSet] invertedSet]
That said, if you're doing a lot of this, you may want to consider using CTFramesetter to do your layout instead of UILabel. Then you can use CTRunGetImageBounds to calculate actual rects. You wouldn't have to calculate your word breaks, since CTFrame will already have done this for you (and it would be guaranteed to be the same algorithm).

How do I count the occurrences of a byte in NSData on an iphone?

I'm new to iOS and Objective C and I'm having trouble figuring out how to use NSData correctly.
I want to count the number of new lines in my data.
// filedata is pulled from a URL asyn
NSInteger knt = 0;
NSInteger len = filedata.length;
const char *pointer = [filedata bytes];
for (NSInteger spot = 0; spot < len; spot++) {
if (pointer[spot] == 10) { // 10 is new line
knt++;
}
}
The count is off, is there a better way to do this?
Try checking for carriage returns as well (ascii 13 http://www.asciitable.com/).
Make sure the newlines are TRULY newlines (ascii 10). You can try this by opening up your data in a hex editor. Hex editors generally will show you text in a right pane, bytes in a middle pain, and addresses of the bytes in a left pane.
If this doesn't resolve your question, please consider posting sample data.

Resources