Extract a 8 digit number from string of variable size - objective-c

I have a string of undetermined size which contains a 8 digit number. Example:
This is 123456 a string
This is a new string 123456
123456 This is another string
How can I extract the integer value of such number?

NSString has an instance method -integerValue which returns the integer value extracted from the string's contents. So [#"123456" integerValue] will return 123456.

I think what you want is an NSScanner. Have the scanner scan up to the first occurrence of the decimalDigitCharacterSet and then use scanInteger: to get the NSInteger value it finds.

You can use regular expressions to pull numbers of any given format out of a string. If you just wanted to grab one integer from any given string (in this case, the first integer):
NSString* str = #"This is 123456 a string";
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#".*?(\\d+).*?" options:NULL error:nil];
NSArray* results = [regex matchesInString:str options:NULL range:NSMakeRange(0, [str length])];
NSString* str2 = [str substringWithRange:[(NSTextCheckingResult*)[results objectAtIndex:0] rangeAtIndex:1]];
NSLog(#"%#",str2);
NSInteger intResult = [str2 integerValue];

Extract a number of the given digits from a string of undeterminate length.
#import <Foundation/Foundation.h>
NSNumber* numberFromStringWithDigits(NSString* string, NSUInteger digits)
{
NSScanner *scanner = [NSScanner scannerWithString:string];
NSCharacterSet *allowed = [NSCharacterSet decimalDigitCharacterSet];
while ([scanner isAtEnd] == NO) {
NSString *buffer;
if ([scanner scanCharactersFromSet:allowed intoString:&buffer]) {
if ([buffer length]==digits){
return [NSNumber numberWithInt:[buffer integerValue]];
}
} else {
[scanner setScanLocation:([scanner scanLocation] + 1)];
}
}
return nil;
}
int main(int argc, char *argv[]) {
#autoreleasepool {
NSString *url = #"http://garb23age.com/x555xx/xx12345678xxxxxx";
NSDate *startTime = [NSDate date];
NSNumber *n = numberFromStringWithDigits(url,8);
NSTimeInterval elapsedTime = [startTime timeIntervalSinceNow];
NSLog(#"%# in %f seconds",n,-elapsedTime); // 12345678 in 0.000188 seconds
}
}
#Bri An C: probably what you want is to extract the parameterString of the NSURL. Maybe you should post the URL to ask for alternate solutions.

Related

Add 1 to a number in an NSString that contains characters Objective-C

I am new to learning Objective-C (my first programming language!) and trying to write a little program that will add 1 to a number contained within a string. E.g. AA1BB becomes AA2BB.
.
So far I have tried to extract the number and add 1. Then extract the letters and add everything back together in a new string. I have had some success but can't manage to get back to the original arrangement of the initial string.
The code I have so far gives a result of 2BB and disregards the characters before the number which is not what I am after (the result I am trying for with this example would be AA2BB). I can't figure out why!
NSString* aString = #"AA1BB";
NSCharacterSet *numberCharset = [NSCharacterSet characterSetWithCharactersInString:#"0123456789-"]; //Creating a set of Characters object//
NSScanner *theScanner = [NSScanner scannerWithString:aString];
int someNumbers = 0;
while (![theScanner isAtEnd]) {
// Remove Letters
[theScanner scanUpToCharactersFromSet:numberCharset
intoString:NULL];
if ([theScanner scanInt:&someNumbers]) {}
}
NSCharacterSet *letterCharset = [NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
NSScanner *letterScanner = [NSScanner scannerWithString:aString];
NSString* someLetters;
while (![letterScanner isAtEnd]) {
// Remove numbers
[letterScanner scanUpToCharactersFromSet:letterCharset
intoString:NULL];
if ([letterScanner scanCharactersFromSet:letterCharset intoString:&someLetters]) {}
}
++someNumbers; //adds +1 to the Number//
NSString *newString = [[NSString alloc]initWithFormat:#"%i%#", someNumbers, someLetters];
NSLog (#"String is now %#", newString);
This is an alternative solution with Regular Expression.
It finds the range of the integer (\\d+ is one or more digits), extracts it, increments it and replaces the value at the given range.
NSString* aString = #"AA1BB";
NSRange range = [aString rangeOfString:#"\\d+" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
NSInteger numericValue = [aString substringWithRange:range].integerValue;
numericValue++;
aString = [aString stringByReplacingCharactersInRange:range withString:[NSString stringWithFormat:#"%ld", numericValue]];
}
NSLog(#"%#", aString);

Simple Objective C program - It can't be this complex

I'm in the process of learning Objective C and decided to create a simple command line program. The idea is that is asks you for your name and then displays it backwards, capitalizing the first letter of each word. I got it done but the solution seems overly complex. I can't help but feel there is a better way.
char word [256];
printf("What is your name: ");
scanf("%[^\n]s",word);
// Convert the char array to NSString
NSString * inputString = [[NSString alloc] initWithCString: word encoding: NSUTF8StringEncoding];
//This will be our output string
//NSString *nameReversed = [[NSString alloc] init]; //alloc, init are needed to create an instance of this object
NSString *nameReversed = #"";
// Make inputString all lower case
inputString = [inputString lowercaseString];
// Get length of inputString and type cast it as an int and decrement by one
int length = (int)([inputString length])-1;
BOOL foundSpace = NO;
for (int i = 0; i<=(length); i++) {
// Setup the range
NSRange range = NSMakeRange(length-i,1);
// Get the a char from the input string
NSString *inputChar = [inputString substringWithRange:range];
// If this is the first char then make it upper case
if (i==0) {
inputChar = [inputChar capitalizedString];
}
// See if the last char was a space and if so make this char upper case
if (foundSpace){
foundSpace = NO; // Reset foundSpace
// Set this char to upper case
inputChar = [inputChar capitalizedString];
}
// See if this char is a space. If so, we'll need to convert the next char to upper case
if ([inputChar isEqual: #" "]) {
foundSpace = YES;
}
// Add the char to nameReversed
nameReversed = [nameReversed stringByAppendingString:inputChar];
}
printf("%s \n", [nameReversed UTF8String]);
Any insight would be appreciated!
Your program doesn't handle composed character sequences properly.
Also, capitalizedString will capitalize the first letter of each word in the string. So you can just call it once.
static NSString *reversedString(NSString *string) {
NSMutableString *reversed = [NSMutableString stringWithCapacity:string.length];
[string enumerateSubstringsInRange:NSMakeRange(0, string.length)
options:NSStringEnumerationReverse
| NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversed appendString:substring];
}];
return reversed;
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSData *inputData = [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile];
NSString *original = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
NSString *reversed = reversedString(original);
NSString *reversedAndCapitalized = [reversed capitalizedString];
printf("%s\n", reversedAndCapitalized.UTF8String);
}
return 0;
}
In a real app I'd probably add a category on NSString defining a reversedString method, instead of making it a free function.
If you assume the input is in ascii encoding.
char word [256];
printf("What is your name: ");
scanf("%[^\n]s", word);
// reverse
for (NSInteger i=0,j=strlen(word)-1; i<j; i++,j--) {
char tmp = word[i];
word[i] = word[j];
word[j] = tmp;
}
NSString *str0 = [NSString stringWithCString:word encoding:NSASCIIStringEncoding];
NSLog(#"%#", [str0 capitalizedString]);

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);

Find certain character and substring in Objective-C

I have a string..
NSString* string = #"%B999999^PDVS123456789012^PADILLA L. ^0X0000399 ?*;999999554749123456789012=00X990300000?*
What I want is to get the name PADILLA L. and 999999554749123456789012=00X990300000?*
Use NSString componentsSeparatedByString: to split the string up. First use #"^". The name will be at index 2. Then split the substring at index 3 using #";". The string at index 1 will give you the 2nd piece you want.
NSArray *substrings = [string componentsSeparatedByString:#"^"];
NSString *name = substrings[2];
name = [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *lastpart = substrings[3];
NSArray *moresubstrings = [lastpart componentsSeparatedByString:#";"];
NSString *secondPiece = moresubstrings[1];
Without more specifics here is a brute force way:
NSString* string = #"%B999999^PDVS123456789012^PADILLA L. ^0X0000399 ?*;999999554749123456789012=00X990300000?*";
NSRange nameRange = {26, 10};
NSString *name = [string substringWithRange:nameRange];
NSRange numRange = {80, 39};
NSString *num = [string substringWithRange:numRange];
The documentation is your friend: NSString Class Reference
Without knowing what the exact input pattern is (we have your n-of-1 example only), it's going to hard to say exactly how you might parse this properly; but NSRegularExpression offers what you need (in addition to other suggested approaches):
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSString *sampleText = #"%B999999^PDVS123456789012^PADILLA L. ^0X0000399 ?*;999999554749123456789012=00X990300000?*";
NSError *regexError = nil;
NSRegularExpressionOptions options = 0;
NSString *pattern = #"^%\\w+\\^\\w+\\^([A-Za-z\\s]+\\.).+\\?\\*\\;(.+)\\?\\*$";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern options:options error:&regexError];
NSTextCheckingResult *match = [expression firstMatchInString:sampleText options:0 range:range];
if( match ) {
NSRange nameRange = [match rangeAtIndex:1];
NSRange numberRange = [match rangeAtIndex:2];
printf("name = %s ",[[sampleText substringWithRange:nameRange] UTF8String]);
printf("number = %s\n",[[sampleText substringWithRange:numberRange] UTF8String]);
}
}
}
This little Foundation application prints the following to the console:
name = PADILLA L. number = 999999554749123456789012=00X990300000
The regex used to analyze the input string may need to be tweaked depending on how the input string varies. Right now it is (unescaped):
^%\w+\^\w+\^([A-Za-z\s]+\.).+\?\*\;(.+)\?\*$

Replace characters in NSString

I am trying to replace all characters except last 4 in a String with *'s.
In objective-c there is a method in NSString class replaceStringWithCharactersInRange: withString: where I would give it range (0,[string length]-4) ) with string #"*". This is what it does: 123456789ABCD is modified to *ABCD while I am looking to make ********ABCD.
I understand that it replaced range I specified with string object. How to accomplish this ?
NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\d" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *newString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:#"*"];
This looks like a simple problem... get the first part string and return it with the last four characters appended to it.
Here is a function that returns the needed string :
-(NSString *)neededStringWithString:(NSString *)aString {
// if the string has less than or 4 characters, return nil
if([aString length] <= 4) {
return nil;
}
NSUInteger countOfCharToReplace = [aString length] - 4;
NSString *firstPart = #"*";
while(--countOfCharToReplace) {
firstPart = [firstPart stringByAppendingString:#"*"];
}
// range for the last four
NSRange lastFourRange = NSMakeRange([aString length] - 4, 4);
// return the combined string
return [firstPart stringByAppendingString:
[aString substringWithRange:lastFourRange]];
}
The most unintuitive part in Cocoa is creating the repeating stars without some kind of awkward looping. stringByPaddingToLength:withString:startingAtIndex: allows you to create a repeating string of any length you like, so once you have that, here's a simple solution:
NSInteger starUpTo = [string length] - 4;
if (starUpTo > 0) {
NSString *stars = [#"" stringByPaddingToLength:starUpTo withString:#"*" startingAtIndex:0];
return [string stringByReplacingCharactersInRange:NSMakeRange(0, starUpTo) withString:stars];
} else {
return string;
}
I'm not sure why the accepted answer was accepted, since it only works if everything but last 4 is a digit. Here's a simple way:
NSMutableString * str1 = [[NSMutableString alloc]initWithString:#"1234567890ABCD"];
NSRange r = NSMakeRange(0, [str1 length] - 4);
[str1 replaceCharactersInRange:r withString:[[NSString string] stringByPaddingToLength:r.length withString:#"*" startingAtIndex:0]];
NSLog(#"%#",str1);
You could use [theString substringToIndex:[theString length]-4] to get the first part of the string and then combine [theString length]-4 *'s with the second part. Perhaps their is an easier way to do this..
NSMutableString * str1 = [[NSMutableString alloc]initWithString:#"1234567890ABCD"];
[str1 replaceCharactersInRange:NSMakeRange(0, [str1 length] - 4) withString:#"*"];
NSLog(#"%#",str1);
it works
The regexp didn't work on iOS7, but perhaps this helps:
- (NSString *)encryptString:(NSString *)pass {
NSMutableString *secret = [NSMutableString new];
for (int i=0; i<[pass length]; i++) {
[secret appendString:#"*"];
}
return secret;
}
In your case you should stop replacing the last 4 characters. Bit crude, but gets the job done