How would you parse the location text from Twitter to get the latitude/longitude in Objective-C? - objective-c

The location text from Twitter could be just about anything. Sometimes Twitter clients set the location with the user's latitude and longitude in the following format.
"\U00dcT: 43.05948,-87.908409"
Since there is no built-in support for Regular Expressions in Objective-C I am considering using the NSString functions like rangeOfString to pull the float values out of this string.
For my current purpose I know the values with start with 43 and 87 so I can key off those values this time but I would prefer to do better than that.
What would you do to parse the latitude/longitude from this string?

This way won't create nearly as many intermediate objects:
float latitude, longitude;
NSString *exampleString = #"\U00dcT: 43.05948,-87.908409";
NSScanner *scanner = [NSScanner scannerWithString:exampleString];
NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];
[scanner scanUpToCharactersFromSet:digits intoString:null];
[scanner scanFloat:&lattitude];
[scanner scanUpToCharactersFromSet:digits intoString:null];
[scanner scanFloat:&longitude];

This appears to work well but I am still interested in what other approaches could work better.
- (CLLocation *)parseLocationText:(NSString *)lt {
// location = "\U00dcT: 43.05948,-87.908409";
NSString *strippedString = [lt stringByTrimmingCharactersInSet:[NSCharacterSet letterCharacterSet]];
NSLog(#"strippedString: %#", strippedString);
if ([strippedString rangeOfString:#","].location != NSNotFound) {
NSArray *chunks = [strippedString componentsSeparatedByString: #","];
if (chunks.count == 2) {
NSLog(#"lat: %#", [chunks objectAtIndex:0]);
NSLog(#"long: %#", [chunks objectAtIndex:1]);
NSString *latitude = [chunks objectAtIndex:0];
NSString *longitude = [chunks objectAtIndex:1];
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[loc autorelease];
return loc;
}
}
return nil;
}

Related

How to parse a string format like [***]***?

I need to parse a string like [abc]000, and what I want to get is an array containing abc and 000. Is there an easy way to do it?
I'm using code like this:
NSString *sampleString = #"[abc]000";
NSArray *sampleParts = [sampleString componentsSeparatedByString:#"]"];
NSString *firstPart = [[[sampleParts objectAtIndex:0] componentsSeparatedByString:#"["] lastObject];
NSString *lastPart = [sampleParts lastObject];
But it's inefficient and didn't check whether the string is in a format like [**]**.
For this simple pattern, can just parse yourself like:
NSString *s = #"[abc]000";
NSString *firstPart = nil;
NSString *lastPart = nil;
if ([s characterAtIndex: 0] == '[') {
NSUInteger i = [s rangeOfString:#"]"].location;
if (i != NSNotFound) {
firstPart = [s substringWithRange:NSMakeRange(1, i - 1)];
lastPart = [s substringFromIndex:i + 1];
}
}
Or you could learn to use the NSScanner class.
As always, there are lots of ways to do this.
OPTION 1
If these are fixed length strings (each part is always three characters) then you can simply get the substrings directly:
NSString *sampleString = #"[abc]000";
NSString *left = [sampleString substringWithRange:NSMakeRange(1, 3)];
NSString *right = [sampleString substringWithRange:NSMakeRange(5, 3)];
NSArray *parts = #[ left, right ];
NSLog(#"%#", parts);
OPTION 1 (shortened)
NSArray *parts = #[ [sampleString substringWithRange:NSMakeRange(1, 3)],
[sampleString substringWithRange:NSMakeRange(5, 3)] ];
NSLog(#"%#", parts);
OPTION 2
If they aren't always three characters, then you can use NSScanner:
NSString *sampleString = #"[abc]000";
NSScanner *scanner = [NSScanner scannerWithString:sampleString];
// Skip the first character if we know that it will always start with the '['.
// If we can not make this assumption, then we would scan for the bracket instead.
scanner.scanLocation = 1;
NSString *left, *right;
// Save the characters until the right bracket into a string which we store in left.
[scanner scanUpToString:#"]" intoString:&left];
// Skip the right bracket
scanner.scanLocation++;
// Scan to the end (You can use any string for the scanUpToString that doesn't actually exist...
[scanner scanUpToString:#"\0" intoString:&right];
NSArray *parts = #[ left, right ];
NSLog(#"%#", parts);
RESULTS (for all options)
2013-05-10 00:25:02.031 Testing App[41906:11f03] (
abc,
000
)
NOTE
All of these assume well-formed strings, so you should include your own error checking.
try like this ,
NSString *sampleString = #"[abc]000";
NSString *pNRegex = #"\\[[a-z]{3}\\][0-9]{3}";
NSPredicate *PNTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pNRegex];
BOOL check=[PNTest evaluateWithObject:sampleString ];
NSLog(#"success:%i",check);
if success comes as 1 then you can perform the action for separating string into array.

Obj-C: Create Array From String Where items are in <>

I am trying to parse a String to an Array each item is between <> for example <this is column 1><this is column 2> etc....
Help would be much appreciated.
Thanks
Something to demonstrate:
NSString *string = #"<this is column 1><this is column 2>";
NSScanner *scanner = [NSScanner scannerWithString:string];
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
NSString *temp;
while ([scanner isAtEnd] == NO)
{
// Disregard the result of the scanner because it returns NO if the
// "up to" string is the first one it encounters.
// You should still have this in case there are other characters
// between the right and left angle brackets.
(void) [scanner scanUpToString:#"<" intoString:NULL];
// Scan the left angle bracket to move the scanner location past it.
(void) [scanner scanString:#"<" intoString:NULL];
// Attempt to get the string.
BOOL success = [scanner scanUpToString:#">" intoString:&temp];
// Scan the right angle bracket to move the scanner location past it.
(void) [scanner scanString:#">" intoString:NULL];
if (success == YES)
{
[array addObject:temp];
}
}
NSLog(#"%#", array);
NSString *input =#"<one><two><three>";
NSString *strippedInput = [input stringByReplacingOccurencesOfString: #">" withString: #""]; //strips all > from input string
NSArray *array = [strippedInput componentsSeperatedByString:#"<"];
Note that [array objectAtIndex:0] will be an empty string ("") an this doesn't work of course, if one of the "actual" string contain < or >
One approach might be to use either componentsSeparatedByCharactersInSet or componentsSeparatedByString from NSString.
NSString *test = #"<one> <two> <three>";
NSArray *array1 = [test componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
NSArray *array2 = [test componentsSeparatedByString:#"<"];
You'll need to do some cleaning up afterward, either trimming in the case of array2 or removing white-space strings in the case of array1

NSString with Emojis

I have a NSArray containing NSStrings with emoji codes in the following format:
0x1F463
How can I now convert them into a NSString with the correct format?
With this method I am able to generate an "Emoji"-NSString:
NSString *emoji = [NSString stringWithFormat:#"\U0001F463"];
But this is only possible with constant NSStrings. How can I convert the whole NSArray?
Not my best work, but it appears to work:
for (NSString *string in array)
{
#autoreleasepool {
NSScanner *scanner = [NSScanner scannerWithString:string];
unsigned int val = 0;
(void) [scanner scanHexInt:&val];
NSString *newString = [[NSString alloc] initWithBytes:&val length:sizeof(val) encoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"%#", newString);
[newString release]; // don't use if you're using ARC
}
}
Using an array of four of your sample value, I get four pairs of bare feet.
You can do it like this:
NSString *str = #"0001F463";
// Convert the string representation to an integer
NSScanner *hexScan = [NSScanner scannerWithString:str];
unsigned int hexNum;
[hexScan scanHexInt:&hexNum];
// Make a 32-bit character from the int
UTF32Char inputChar = hexNum;
// Make a string from the character
NSString *res = [[NSString alloc] initWithBytes:&inputChar length:4 encoding:NSUTF32LittleEndianStringEncoding];
// Print the result
NSLog(#"%#", res);

Objective C read csv file and use array

I have a csv file as this:
1#one#two#three#four;
2#apple#tower#flower#robot;
I read this file with this code:
NSString *resourceFileName = #"PrenotazioniDb";
NSString *pathToFile =[[NSBundle mainBundle] pathForResource: resourceFileName ofType: #"txt"];
NSError *error;
NSString *fileString = [NSString stringWithContentsOfFile:pathToFile encoding:NSUTF8StringEncoding error:&error];
if (!fileString) {
NSLog(#"Error reading file.");
}
NSScanner *scanner = [NSScanner scannerWithString:fileString];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:#"\n#; "]];
NSString *one = nil, *two = nil, *three = nil, *four = nil;
while ([scanner scanUpToString:#"#" intoString:&one] && [scanner scanUpToString:#"#" intoString:&two] && [scanner scanUpToString:#"#" intoString:&three] && [scanner scanUpToString:#"#" intoString:&four]{
}
but I want memorize the file in an array, What can I do? I should use two array: one for line and one for single word; for example in first array in a position I store
1#one#two#three#four;
and in the second array I store in first position "1" in second "one" in third "two" ext....
What Can i Do?
You can use the componentsSeparatedByString method.
NSString *list=#"1#one#two#three#four";
NSArray *listItems = [list componentsSeparatedByString:#"#"];
NSLog(#"listItems= %#",listItems);
prints:
listItems= (
1,
one,
two,
three,
four
)

How to use NSScanner?

I've just read Apple documentation for NSScanner.
I'm trying to get the integer of this string:
#"user logged (3 attempts)"
I can't find any example, how to scan within parentheses. Any ideas?
Here's the code:
NSString *logString = #"user logged (3 attempts)";
NSScanner *aScanner = [NSScanner scannerWithString:logString];
[aScanner scanInteger:anInteger];
NSLog(#"Attempts: %i", anInteger);
Ziltoid's solution works, but it's more code than you need.
I wouldn't bother instantiating an NSScanner for the given situation. NSCharacterSet and NSString give you all you need:
NSString *logString = #"user logged (3 attempts)";
NSString *digits = [logString stringByTrimmingCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
NSLog(#"Attempts: %i", [digits intValue]);
or in Swift:
let logString = "user logged (3 attempts)"
let nonDigits = NSCharacterSet.decimalDigitCharacterSet().invertedSet
let digits : NSString = logString.stringByTrimmingCharactersInSet(nonDigits)
NSLog("Attempts: %i", digits.intValue)
`Here is what I do to get certain values out of a string
First I have this method defined
- (NSString *)getDataBetweenFromString:(NSString *)data leftString:(NSString *)leftData rightString:(NSString *)rightData leftOffset:(NSInteger)leftPos;
{
NSInteger left, right;
NSString *foundData;
NSScanner *scanner=[NSScanner scannerWithString:data];
[scanner scanUpToString:leftData intoString: nil];
left = [scanner scanLocation];
[scanner setScanLocation:left + leftPos];
[scanner scanUpToString:rightData intoString: nil];
right = [scanner scanLocation] + 1;
left += leftPos;
foundData = [data substringWithRange: NSMakeRange(left, (right - left) - 1)]; return foundData;
}
Then call it.
foundData = [self getDataBetweenFromString:data leftString:#"user logged (" rightString:#"attempts)" leftOffset:13];
leftOffset is the number of characters for the left string
Could be an easier cleaner way but that was my solution.
Here is a simple solution using NSScanner (yes, #NSResponder has a really neat solution!):
NSString *logString = #"user logged (3 attempts)";
NSString *numberString;
NSScanner *scanner = [NSScanner scannerWithString:logString];
[scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil];
[scanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&numberString];
NSLog(#"Attempts: %i", [numberString intValue]);
NSLog output:
Attempts: 3
NSScanner is a linear scanner. You have to scan through the stuff you don't want to get to what you do want.
You could do [aScanner scanUpToCharactersInSet:[NSCharacterSet decimalDigitCharacterSet] intoString:NULL] to jump past everything up to the number character. Then you do [aScanner scanInteger:&anInteger] to scan the character into an integer.
here is the reg-ex usage
NSString *logString = #"user logged (3 attempts)";
NSString * digits = [logString stringByMatching:#"([+\\-]?[0-9]+)" capture:1];