95

I would like to know how to parse a hex string, representing a number, in Objective-C. I am willing to use both an objective, or a C-based method, either is fine.

example:

#01FFFFAB

should parse into the integer: 33554347

Any help would be appreciated!

Quintin Willison
  • 610
  • 6
  • 13
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201

7 Answers7

172

Joshua Weinberg's answer is mostly correct, however the 0x prefix is optional when scanning hexadecimal integers. If you have a string in the format #01FFFFAB, you can still use NSScanner, but you can skip the first character.

unsigned result = 0;
NSScanner *scanner = [NSScanner scannerWithString:@"#01FFFFAB"];

[scanner setScanLocation:1]; // bypass '#' character
[scanner scanHexInt:&result];
Ron
  • 3,055
  • 1
  • 20
  • 21
dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • Note that if you want to perform strict parsing, you should first check that the string does not begin with `0x` (or `0X`). NSScanner will accept those prefixes. – Chris Page May 02 '19 at 00:37
65

you can use NSScanner for this

unsigned int outVal;
NSScanner* scanner = [NSScanner scannerWithString:@"0x01FFFFAB"];
[scanner scanHexInt:&outVal];

outVal will contain the int you're looking for. The 0x is optional.

Alex Terente
  • 12,006
  • 5
  • 51
  • 71
Joshua Weinberg
  • 28,598
  • 2
  • 97
  • 90
12

strtol() is your friend.

It converts a string to a long, and you can pass the base of the number in. Strip that # sign off first though, or pass to strtol a pointer to the first numerical character.

Graham Perks
  • 23,007
  • 8
  • 61
  • 83
  • 1
    I'm going with this method, way simpler (and potentially quicker) than allocating an nsscanner. – Chris Jun 01 '11 at 06:25
  • 1
    @Chris: It's probably no quicker if you have an NSString, because you'd need to convert the NSString to a C string before you can use strtol. If you already have the text in a C string, it will probably be faster, but unless you are doing this thousands or millions of times I doubt you'd feel the performance hit. – dreamlax Dec 06 '11 at 21:30
  • 4
    int res = strtol( [yourString UTF8String], NULL, base) – loretoparisi Nov 28 '13 at 18:55
  • 2
    @dreamlax The definition of -[NSString UTF8String] shows that it returns a pointer to the backing UTF8 C string (NS_RETURNS_INNER_POINTER). At a high level, it's only a single operation to return this const char pointer versus the overhead of allocating memory for NSScanner, copying the NSString input parameter, not to mention the additional ObjC message-passing latency incurred with each ObjC method invocation. It's algorithmically much faster to use strtoull(), but you likely won't observe the difference unless you're benchmarking scanning hex integers from millions of strings :-) – Jacob Sep 02 '16 at 23:06
  • @Jacob: `NSString` objects are stored as UTF-16, not UTF-8 (as per the [documentation](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/)), so conversion to UTF-8 is first required (which is potentially costly), whereas the `NSScanner` *may* be optimised for UTF-16. The `NS_RETURNS_INNER_POINTER` is an annotation that extends the lifetime of an object until the last use of the returned pointer (or any pointer derived from it). See [here](http://clang.llvm.org/docs/AutomaticReferenceCounting.html#interior-pointers). It's for ARC / GC. – dreamlax Sep 03 '16 at 11:57
  • 1
    The `strtol` function is also a lot more lenient. Write thorough unit tests (include spaces, non-hex characters, etc..) as you will find some surprising edge cases that `NSScanner` gives you more control over. – Quintin Willison Mar 30 '17 at 14:15
6

You can use the below line for conversion. Its just one line code:

NSString *hexString = @"01FFFFAB";
length = (UInt64)strtoull([hexString UTF8String], NULL, 16);
NSLog(@"The required Length is %d", length);

Happy Coding!!!

carbonr
  • 6,049
  • 5
  • 46
  • 73
Sahil Mahajan
  • 3,922
  • 2
  • 29
  • 43
  • Note that if you want to perform strict parsing, you should first check that the string does not begin with `0x` (or `0X`) or +/- or any other characters that are not considered valid in your input. – Chris Page May 02 '19 at 00:39
2

Swift 4 standard library introduced new initializer for parsing all integer types. It takes string to parse with radix (i.e. base) and returns optional integer:

let number = Int("01FFFFAB", radix: 16)!
Alexander Vasenin
  • 11,437
  • 4
  • 42
  • 70
0

According to apple:

An NSScanner object interprets and converts the characters of an NSString object into number and string values.

so, if u have NSData obj u can do next

NSString *dataDescription = data.description;
NSString *dataAsString = [dataDescription substringWithRange:NSMakeRange(1, [dataDescription length]-2)];
unsigned intData = 0;
NSScanner *scanner = [NSScanner scannerWithString:dataAsString];
[scanner scanHexInt:&intData];
hbk
  • 10,908
  • 11
  • 91
  • 124
  • Note that if you want to perform strict parsing, you should first check that the string does not begin with `0x` (or `0X`) or any other characters that are not considered valid in your input, but which are accepted by NSScanner. – Chris Page May 02 '19 at 00:40
0

For Swift 3:

var hex = "#01FFFFAB"
hex.remove(at: hex.startIndex)
var rgbValue:UInt32 = 0
Scanner(string: hex).scanHexInt32(&rgbValue)
// rgbValue == 33554347
jnelson
  • 1,215
  • 10
  • 16