Scan string, get info. Xcode - objective-c

I have made an app which the user types in data and it gets a url from google maps like this - [https://www.google.com.au/maps/search/nearest+pizza+shop/#-27.4823545,153.0297855,12z/data=!3m1!4b1
In the middle you see 27.4823545,153.0297855 this is long and lat. So with this I can make my maps work. But I really need to know how to scan this string (the url was made into a string) and get only those numbers, I have already tried this ->
NSString *currentURL = web.request.URL.absoluteString;
string1 = currentURL;
NSScanner *scanner = [NSScanner scannerWithString:string1];
NSString *token = nil;
[scanner scanUpToString:#"#" intoString:NULL];
[scanner scanUpToString:#"z" intoString:&token];
label.text = token;
I think it would be highly likely I did a mistake, since I am new to objective-c, but if there are more effective ways please share . :)
Thanks for all the people who took the time to help.
Bye All!

A solution:
Extrating the path from an NSURL. Then looking at each path components to extract the coordinates components :
NSURL *url = [NSURL URLWithString:#"https://www.google.com.au/maps/search/nearest+pizza+shop/#-27.4823545,153.0297855,12z/data=!3m1!4b1"];
NSArray *components = [url.path componentsSeparatedByString:#"/"];
NSArray *results = nil;
for (NSString *comp in components) {
if ([comp length] > 1 && [comp hasPrefix:#"#"]) {
NSString *resultString = [comp substringFromIndex:1]; // removing the '#'
results = [resultString componentsSeparatedByString:#","]; // lat, lon, zoom
break;
}
}
NSLog(#"results: %#", results);
Will print:
results: (
"-27.4823545",
"153.0297855",
12z
)
This solution gives you a lot of control points for data validation.
Hope this helps.
Edit:
To get rid of the "z". I would treat that as a special number with a number formatter in decimal style and specify that character as the positive and negative suffix:
NSString *targetStr = #"12z";
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
formatter.positiveSuffix = #"z";
formatter.negativeSuffix = #"z";
NSNumber *result = [formatter numberFromString:targetStr];
The var result will contain whatever positive or negative number before the 'z'. You could use a NSScanner to do the trick but I believe it's less flexible.
As a side note, it would be great to get that "z" (zoom's character) from Google's API. If they ever change it to something else your number will still be parsed properly.

Related

Extract only DIGIT in Objective c [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have string this, Total Bill : $22.00, I just want to extract 22 from this string, i'm confused how to get that, I have tried some code but it gives me 2200 rather than 22. My code is this,
NSString * val = #"Total Bill : $22.00";
NSString *newString = [[val componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:#""];
NSLog(#"VV %#",newString);
The simplest is to find the location of the $ and then return the rest of the string. This will give you the 22.00.
NSString *val = #"Total Bill : $22.00";
NSRange dollar = [val rangeOfString:#"$"];
NSRange decimal = [val rangeOfString:#"."];
if (dollar.location != NSNotFound && decimal.location != NSNotFound) {
NSRange range = NSMakeRange(dollar.location + 1, decimal.location - dollar.location - 1)
NSString *amount = [val substringWithRange:range];
NSLog(#"VV %#",amount);
} else {
NSLog(#"No dollar sign or decimal found");
}
One option is to use a NSCharacterSet union with the characters you want to keep (currency separator -- decimal point in your case).. then invert it. Split the string and then join it using this character set. Then you can use NSNumberFormatter to get the result..
NSString *stringToParse = #"Total Blah: $22.00";
NSMutableCharacterSet *characterSet = [NSMutableCharacterSet decimalDigitCharacterSet];
[characterSet formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:#".,"]];
stringToParse = [[stringToParse componentsSeparatedByCharactersInSet:[characterSet invertedSet]] componentsJoinedByString:#""];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMinimumFractionDigits:0];
[formatter setMaximumFractionDigits:0];
[formatter setPartialStringValidationEnabled:YES];
NSString *str = [formatter stringFromNumber:[formatter numberFromString:stringToParse]];
NSLog(#"%#", str);
You can use NSScanner to extract values like this from a string.
Depending on the type you want, you can use scanDouble:, scanInt: or something else. Here's an example:
NSString *myString = #"Total Bill : $22.00";
NSScanner *scanner = [[NSScanner alloc] initWithString:myString];
// Moves the scanner to the "$" character, then eats that character
[scanner scanUpToString:#"$" intoString:nil];
[scanner scanString:#"$" intoString:nil];
// Here you have options, can scan as a double or an integer, or convert later.
double val = 0;
[scanner scanDouble:&val];

Get a substring from an NSString until arriving to any letter in an NSArray - objective C

I am trying to parse a set of words that contain -- first greek letters, then english letters. This would be easy if there was a delimiter between the sets.That is what I've built so far..
- (void)loadWordFileToArray:(NSBundle *)bundle {
NSLog(#"loadWordFileToArray");
if (bundle != nil) {
NSString *path = [bundle pathForResource:#"alfa" ofType:#"txt"];
//pull the content from the file into memory
NSData* data = [NSData dataWithContentsOfFile:path];
//convert the bytes from the file into a string
NSString* string = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSUTF8StringEncoding];
//split the string around newline characters to create an array
NSString* delimiter = #"\n";
incomingWords = [string componentsSeparatedByString:delimiter];
NSLog(#"incomingWords count: %lu", (unsigned long)incomingWords.count);
}
}
-(void)parseWordArray{
NSLog(#"parseWordArray");
NSString *seperator = #" = ";
int i = 0;
for (i=0; i < incomingWords.count; i++) {
NSString *incomingString = [incomingWords objectAtIndex:i];
NSScanner *scanner = [NSScanner localizedScannerWithString: incomingString];
NSString *firstString;
NSString *secondString;
NSInteger scanPosition;
[scanner scanUpToString:seperator intoString:&firstString];
scanPosition = [scanner scanLocation];
secondString = [[scanner string] substringFromIndex:scanPosition+[seperator length]];
// NSLog(#"greek: %#", firstString);
// NSLog(#"english: %#", secondString);
[outgoingWords insertObject:[NSMutableArray arrayWithObjects:#"greek", firstString, #"english",secondString,#"category", #"", nil] atIndex:0];
[englishWords insertObject:[NSMutableArray arrayWithObjects:secondString,nil] atIndex:0];
}
}
But I cannot count on there being delimiters.
I have looked at this question. I want something similar. This would be: grab the characters in the string until an english letter is found. Then take the first group to one new string, and all the characters after to a second new string.
I only have to run this a few times, so optimization is not my highest priority.. Any help would be appreciated..
EDIT:
I've changed my code as shown below to make use of NSLinguisticTagger. This works, but is this the best way? Note that the interpretation for english characters is -- for some reason "und"...
The incoming string is: άγαλμα, το statue, only the last 6 characters are in english.
int j = 0;
for (j=0; j<incomingString.length; j++) {
NSString *language = [tagger tagAtIndex:j scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
if ([language isEqual: #"und"]) {
NSLog(#"j is: %i", j);
int k = 0;
for (k=0; k<j; k++) {
NSRange range = NSMakeRange (0, k);
NSString *tempString = [incomingString substringWithRange:range ];
NSLog (#"tempString: %#", tempString);
}
return;
}
NSLog (#"Language: %#", language);
}
Alright so what you could do is use NSLinguisticTagger to find out the language of the word (or letter) and if the language has changed then you know where to split the string. You can use NSLinguisticTagger like this:
NSArray *tagschemes = #[NSLinguisticTagSchemeLanguage];
NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options: NSLinguisticTagPunctuation | NSLinguisticTaggerOmitWhitespace];
[tagger setString:#"This is my string in English."];
NSString *language = [tagger tagAtIndex:0 scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
//Loop through each index of the string's characters and check the language as above.
//If it has changed then you can assume the language has changed.
Alternatively you can use NSSpellChecker's requestCheckingOfString to get teh dominant language in a range of characters:
NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
[spellChecker setAutomaticallyIdentifiesLanguages:YES];
NSString *spellCheckText = #"Guten Herr Mustermann. Dies ist ein deutscher Text. Bitte löschen Sie diesen nicht.";
[spellChecker requestCheckingOfString:spellCheckText
range:(NSRange){0, [spellCheckText length]}
types:NSTextCheckingTypeOrthography
options:nil
inSpellDocumentWithTag:0
completionHandler:^(NSInteger sequenceNumber, NSArray *results, NSOrthography *orthography, NSInteger wordCount) {
NSLog(#"dominant language = %#", orthography.dominantLanguage);
}];
This answer has information on how to detect the language of an NSString.
Allow me to introduce two good friends of mine.
NSCharacterSet and NSRegularExpression.
Along with them, normalization. (In Unicode terms)
First, you should normalize strings before analyzing them against a character set.
You will need to look at the choices, but normalizing to all composed forms is the way I would go.
This means an accented character is one instead of two or more.
It simplifies the number of things to compare.
Next, you can easily build your own NSCharacterSet objects from strings (loaded from files even) to use to test set membership.
Lastly, regular expressions can achieve the same thing with Unicode Property Names as classes or categories of characters. Regular expressions could be more terse but more expressive.

Check if it is possible to break a string into chunks?

I have this code who chunks a string existing inside a NSString into a NSMutableArray:
NSString *string = #"one/two/tree";
NSMutableArray *parts = [[string componentsSeparatedByString:#"/"] mutableCopy];
NSLog(#"%#-%#-%#",parts[0],parts[1],parts[2]);
This command works perfectly but if the NSString is not obeying this pattern (not have the symbol '/' within the string), the app will crash.
How can I check if it is possible to break the NSString, preventing the app does not crash?
Just check parts.count if you don't have / in your string (or only one), you won't get three elements.
NSString *string = #"one/two/tree";
NSMutableArray *parts = [[string componentsSeparatedByString:#"/"] mutableCopy];
if(parts.count >= 3) {
NSLog(#"%#-%#-%#",parts[0],parts[1],parts[2]);
}
else {
NSLog(#"Not found");
}
From the docs:
If list has no separators—for example, "Karin"—the array contains the string itself, in this case { #"Karin" }.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/componentsSeparatedByString:
You might be better off using the "opposite" function to put it back together...
NSString *string = #"one/two/three";
NSArray *parts = [string componentsSeparatedByString:#"/"];
NSString *newString = [parts componentsJoinedByString:#"-"];
// newString = #"one-two-three"
This will take the original string. Split it apart and then put it back together no matter how many parts there are.

How to leave a set number of spaces in NSString?

I have separate text objects for the unchanging portion (i.e. "Bonus Score: (+7%)") and the changing portion (e.g. "247,890"). Since they're separate, I want to leave space in the unchanging portion to display the number.
What I first tried was:
NSString* numberString = #"247,890";
NSString* blankScore = [#"" stringByPaddingToLength:[numberString length] withString: #" " startingAtIndex:0];
NSString* baseDisplay = [NSString stringWithFormat:#"BONUS SCORE: %# (+7%%)", blankScore];
'blankScore' was the correct length, but the resulting baseDisplay seemed to trim the spaces around where blankScore would be, making it too small of a space for the displayed number.
Next I tried another way of creating blankScore:
NSString* blankScore = [numberString stringByReplacingCharactersInRange:NSMakeRange(0, [numberString length]) withString:#" "];
But this returned a blankScore of length 1.
Am I understanding these NSString methods incorrectly? I checked the docs, and it seems like my understanding of these methods aligns with what's written there, but I still don't understand why I can't get my baseDisplay to have the correct number of spaces.
Have you printed blankScore on the console using NSLog? Actually your string is correct, but the output is trimmed at end of lines - this is why you see it as described.
#H2CO3 is on to the right solution. You should be using:
NSString *baseDisplay = [NSString stringWithFormat:#"BONUS SCORE: %# (+7%%)", numberString];
To make this work even better, you may want to consider an NSNumberFormatter to correctly format the changing part before inserting it into the baseDisplay object. Something like this:
NSNumber *changingNumber = [NSNumber numberWithDouble:247890];
NSNumberFormatter *correctFormat = [[NSNumberFormatter alloc] init];
[correctFormat setNumberStyle:NSNumberFormatterDecimalStyle];
[correctFormat setHasThousandSeparators:YES];
[correctFormat setUsesGroupingSeparator:YES];
NSString *numberString = [correctFormat stringFromNumber:changingNumber];
NSString *baseDisplay = [NSString stringWithFormat:#"BONUS SCORE: %# (+7%%)", numberString];
This way no matter what number you throw at it, it will correctly display "1,234,456" or "34,567", whatever.
EDIT:
Based on the comments to my answer you will need to use:
stringByPaddingToLength:withString:startingAtIndex:
It should look something like this:
NSString *templateString = #"BONUS SCORE:";
NSString *templateString2 = #"(+7%%)";
NSUInteger baseStringLength = [templateString length] + [numberString length];
NSString *spacedString = [templateString stringByPaddingToLength:baseStringLength withString:#" " startingAtIndex:0];
NSString *baseDisplay = [NSString stringWithFormat:#"%#%#", spacedString, templateString2];

NSString: remove leading 0s so '00001234' becomes '1234'? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Removing leading zeroes from a string
I need to remove leading 0s in an NSString, a quick way I can think of is to convert the string to an NSNumber then convert back to NSString which will give me the clean string, although I'm not sure if it works. Is there any other way to do this?
Thanks
So just for fun, I decided to time the various ways of doing this. This was by no means a scientific test, done mostly for my amusement, but some of you might like to see it anyway.
I created a method and substituted the various routines to process strings representing the numbers 0 - 100,000 all with three leading 0's.
Keep in mind however, that even the slowest method is going to be perfectly acceptable if you only have one (or even one hundred) of these strings to trim. (Using the number formatter takes about .000012039905 seconds, or about 1/100th of a millisecond.) Other things such as how easy your code is to read and understand is usually more important unless you really do need to process a large file full of strings like this. My personal favorite is still the regular expression, because it is relatively fast and immediately obvious what you are trying to accomplish, even without documentation.
Here are the results (from fastest to slowest):
Looping through the string
// I tried this by looping through the utf8String and got the same times
// (actually, ever so slightly longer, probably since it had to create the c string)
//
// I did find that using `[string getCharacters:buffer range:range]` and
// iterating over the character buffer that it took another 0.01 seconds
// off the time. Hardly worth it though. :)
NSUInteger length = [string length];
for (NSUInteger i = 0; i < length; i++)
{
if ([string characterAtIndex:i] != '0')
{
return [string substringFromIndex:i];
}
}
return #"0";
// Time 1: 0.210126
// Time 2: 0.219159
// Time 3: 0.201496
Converting to an int and then back to a NSString
int num = [string intValue];
return [NSString stringWithFormat:#"%d", num];
// Time 1: 0.322206
// Time 2: 0.345259
// Time 3: 0.324954
long long num = [string longLongValue];
return [NSString stringWithFormat:#"%lld", num];
// Time 1: 0.364318
// Time 2: 0.344946
// Time 3: 0.364761
// These are only slightly slower, but you can do bigger numbers using long long
Using a NSScanner
NSScanner *scanner = [NSScanner scannerWithString:string];
NSCharacterSet *zeros = [NSCharacterSet
characterSetWithCharactersInString:#"0"];
[scanner scanCharactersFromSet:zeros intoString:NULL];
return [string substringFromIndex:[scanner scanLocation]];
// Time 1: 0.505277
// Time 2: 0.481884
// Time 3: 0.487209
Using a regular expression
NSRange range = [string rangeOfString:#"^0*" options:NSRegularExpressionSearch];
return [string stringByReplacingCharactersInRange:range withString:#""];
// Time 1: 0.610879
// Time 2: 0.645335
// Time 3: 0.637690
Using a static number formatter
static NSNumberFormatter *formatter = nil;
if (formatter == nil)
{
formatter = [NSNumberFormatter new];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
}
NSNumber *number = [formatter numberFromString:string];
return [formatter stringFromNumber:number];
// Time 1: 1.774198
// Time 2: 1.753013
// Time 3: 1.753893
Using a number formatter
NSNumberFormatter *formatter = [NSNumberFormatter new];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
NSNumber *number = [formatter numberFromString:string];
return [formatter stringFromNumber:number];
// Time 1: 11.978336
// Time 2: 12.039905
// Time 3: 11.904984
// No wonder Apple recommends reusing number formatters!
You could use regular expressions.
NSString *numStr = #"0001234";
NSRange range = [numStr rangeOfString:#"^0*" options:NSRegularExpressionSearch];
NSString *result = [numStr stringByReplacingCharactersInRange:range withString:#""];
If you doing it a lot (as in thousands of times) you may benefit from using a compiled NSRegularExpression.
This works, I've tested it. And I think this is a very good way. Less code less bug. KISS.
NSString *numStr = #"000123";
int num = numStr.intValue;
numStr = [NSString stringWithFormat:#"%d", num];