check if string contains number larger than - ios

I have the following NSString:
NSString *testString=#"megaUser 35 youLost 85 noob 10 showTime 36 pwn 110"
I want to know if this string contains a number larger than 80. I do not need to know where, how many or what the actual number is but simply a boolean value (YES or NO). I have thought about regexing the string to remove everything but numbers from it, but after that I am not sure what an efficient way to do the check would be.
In other words, is there a solution that doesnt require breaking the string into array components and then do one at a time check? If anyone knows how this could be done, please let me know!
Thank you!

You can use a scanner for this:
// The string to parse
NSString *testString=#"megaUser 35 youLost 85 noob 10 showTime 36 pwn 110";
// Create a new scanner for this string and tell it to skip everything but numbers
NSScanner *scanner = [[NSScanner alloc] initWithString:testString];
NSCharacterSet *nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
[scanner setCharactersToBeSkipped:nonNumbers];
// Scan integers until we get to the end of the string
// If you will have numbers larger than int, you can use long long and scanLongLong for larger numbers
int largestNumber = 0, currentNumber = 0;
while ([scanner scanInt:&currentNumber] == YES)
{
if (currentNumber > largestNumber)
largestNumber = currentNumber;
}
// See if the number is larger than 80
if (largestNumber > 80)
return YES;
// Nope
return NO;

Related

How to add more strings to the combined string if the length is less than prescribed length?

In iOS I am using two strings to combine and to form a single string. But the combined string must be of 16 characters . So if two strings are small and if we combine both and if it is less than 16 characters I must add few more characters to make it to 16 characters. How to achieve this?
NSString *combined = [NSString stringWithFormat:#"%#%#", stringURL, stringSearch];
This is the code I am using. So if I combine and it is less than 16 characters how to calculate it and add more characters to make it 16 characters?
Something like below
NSString *combined = [NSString stringWithFormat:#"%#%#", stringURL, stringSearch];
if (combined.length < 16)
{
NSString *newCombined = [NSString stringWithFormat:#"%#%#", combined, #"Some new string"];
}
You can use substringWithRange: method from NSString. You can take the below code as an example and modify it as per your requirements.
if (combined.length > 25)
{
NSString *beginning = [combined substringWithRange:NSMakeRange(0, 15)];
NSString *fromEnd = [combined substringWithRange:NSMakeRange(startPoint, combined.length-startPoint)];
}
You could make use of stringWithFormat - basically of printf if you want to pad with just a single char. Below I give some examples which I have constructed to illustrate, so it won't run out the box, but you only need to comment out the ones you do not want to make it work.
// To get 50 spaces
NSString * s50 = [NSString stringWithFormat:#"%*s", 50, ""];
// Pad with these characters, select only 1
// This will pad with spaces
char * pad = "";
// This will pad with minuses - you need enough to fill the whole field
char * pad = "-------------------------------------------------------";
// Some string
NSString * s = #"Hi there";
// Here back and front are just int's. They must be, but they can be calculated,
// e.g. you could have this to pad to 50
int back = 50 - s.length; if ( back < 0 ) back = 0;
// Pad s at the back
int back = 20;
NSString * sBack = [NSString stringWithFormat:#"%#%*s", s, back, pad];
// Pad s in front
int front = 10;
NSString * sFront = [NSString stringWithFormat:#"%*s%#", front, pad, s];
// Pad s both sides
NSString * sBoth = [NSString stringWithFormat:#"%*s%#%*s", front, pad, s, back, pad];
Note that the amounts here are parameterised. I use e.g. 50 in the first line but that could just as well be n as long as n is an int and you can use that to then perform calculations, store it in n and pad. There is an example in the code.
Here is a sample of the output
2020-11-04 08:16:22.908828+0200 FormatSpecifiers[768:15293] [Hi there-------------------------------------------------------]
2020-11-04 08:16:22.908931+0200 FormatSpecifiers[768:15293] [-------------------------------------------------------Hi there]
2020-11-04 08:16:22.908992+0200 FormatSpecifiers[768:15293] [-------------------------------------------------------Hi there-------------------------------------------------------]
I just show how to pad the combined string. To combine the string of course just use stringByAppendingString e.g.
NSString * s = [a stringByAppendingString:b];
and then you can do calcs based on s.length e.g. as shown in the example.

NSScanner to scan until a character or number is Hit

My problem is that I want to extract the data from the string. The strings prints 1000 lines with some random data fetched from web. The string is like this:
Level
1
2
3
4
5
6
7
8
Score
0
0
0
0
0
0
0
0
I need NSScanner to save data in array like this
int *extractedLevelData = {1, 2, 3, 4, 5, 6, 7, 8}
int *extractedScoreData = {0, 0, 0, 0, 0, 0, 0, 0}
The problem is that the row of number in level and score is dynamic, it goes from 1 then new line then 2 then new line then 3 then new line and so on. The challenge is that sometimes it can be 1 to 5 or sometimes it can be 1 only and sometimes maximum is 1 to 8. They show up in the same style as shown above followed by new line character. Same with the "Score".
I've tried this but the saved data returns null in NSLog, it has been 7 days since I'm learning Objective C and I'm almost finished with the app until this problem came.
Here is what I've tried:
NSString *extractedData;
NSCharacterSet *tripleNewLine = [NSCharacterSet characterSetWithCharactersInString:#"\n\n\n"];
[firstScanner scanString:#"Level" intoString:NULL];
[firstScanner setScanLocation:[firstScanner scanLocation]];
[firstScanner scanUpToCharactersFromSet:tripleNewLine intoString:&extractedData];
NSLog(#"%#", extractedData);
Note that this is just a code snippet and the real problem is really complex but if someone smart enough to solve this problem then my problem will be solved! The logic can be: tell the NSScanner to scan from "Level" text with numbers until it hit any character.
So if you don't really want to use NSScanner another solution can be the following:
Split the whole string by Score this will give you two strings one with the values from score and one with the values from level:
`NSArray *components = [serverString componentsSeparatedByString:#"Score"];`
The above line will split your server string in two strings contained by components array. One will have all the values from Level including Level, and the other one will have the values from Score without Score value.
Now you can split those two strings by \n character, this will result in two arrays with all the values from a row.
if(components.count > 1) { //we better check if we have both substrings
NSArray *levels = [[components objectAtIndex:0] componentsSeparatedByString:#"\n"];
NSArray *scores = [[components objectAtIndex:1] componentsSeparatedByString:#"\n"];
}
Now after you have the all the values we should create a method that will check if a value is an actual number, if not we will remove it from the array.
-(NSArray *)checkAndRemoveNonNumbersFromArray:(NSArray *)checkedArray {
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
checkedArray = [checkedArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary *bindings) {
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:evaluatedObject];
return [alphaNums isSupersetOfSet:inStringSet];
}]];
return checkedArray;
}
Now that we have the method created, the code from point 2 will become:
if(components.count > 1) { //we better check if we have both substrings
NSArray *levels = [[components objectAtIndex:0] componentsSeparatedByString:#"\n"];
NSArray *scores = [[components objectAtIndex:1] componentsSeparatedByString:#"\n"];
levels = [self checkAndRemoveNonNumbersFromArray:levels];
scores = [self checkAndRemoveNonNumbersFromArray:scores];
}
Now levels & scores will have only numerical values from those two arrays. Note, this is not the best solution, is more a solution to show you how you can play with strings, after you understand this implementation I think you can find one that uses NSScaner.
I see that you are passing #"Level" as a string input rather than a variable, which is not correct. I assume Level is the NSString object in this case. You can use this solution. This will print all the data from Level
NSScanner *scanner = [NSScanner scannerWithString:Level];
while([scanner isAtEnd] == NO) {
[scanner setScanLocation:[scanner scanLocation]];
[scanner scanUpToCharactersFromSet:tripleNewLine intoString:&extractedData];
NSLog(#"%#", extractedData);
}

How can I count decimal digits?

I have to count how many decimal digits are there in a double in Xcode 5. I know that I must convert my double in a NSString, but can you explain me how could I exactly do? Thanks
A significant problem is that a double has a fractional part which has no defined length. If you know you want, say, 3 fractional digits, you could do:
[[NSString stringWithFormat:#"%1.3f", theDoubleNumber] length]
There are more elegant ways, using modulo arithmetic or logarithms, but how elegant do you want to be?
A good method could be to take your double value and, for each iteration, increment a counter, multiply your value by ten, and constantly check if the left decimal part is really near from zero.
This could be a solution (referring to a previous code made by Graham Perks):
int countDigits(double num) {
int rv = 0;
const double insignificantDigit = 8;
double intpart, fracpart;
fracpart = modf(num, &intpart);
while ((fabs(fracpart) > 0.000000001f) && (rv < insignificantDigit))
{
num *= 10;
fracpart = modf(num, &intpart);
rv++;
}
return rv;
}
You could wrap the double in an instance of NSNumber and get an NSString representation from the NSNumber instance. From there, calculating the number of digits after the decimal could be done.
One possible way would be to implement a method that takes a double as an argument and returns an integer that represents the number of decimal places -
- (NSUInteger)decimalPlacesForDouble:(double)number {
// wrap double value in an instance of NSNumber
NSNumber *num = [NSNumber numberWithDouble:number];
// next make it a string
NSString *resultString = [num stringValue];
NSLog(#"result string is %#",resultString);
// scan to find how many chars we're not interested in
NSScanner *theScanner = [NSScanner scannerWithString:resultString];
NSString *decimalPoint = #".";
NSString *unwanted = nil;
[theScanner scanUpToString:decimalPoint intoString:&unwanted];
NSLog(#"unwanted is %#", unwanted);
// the number of decimals will be string length - unwanted length - 1
NSUInteger numDecimalPlaces = (([resultString length] - [unwanted length]) > 0) ? [resultString length] - [unwanted length] - 1 : 0;
return numDecimalPlaces;
}
Test the method with some code like this -
// test by changing double value here...
double testDouble = 1876.9999999999;
NSLog(#"number of decimals is %lu", (unsigned long)[self decimalPlacesForDouble:testDouble]);
results -
result string is 1876.9999999999
unwanted is 1876
number of decimals is 10
Depending on the value of the double, NSNumber may do some 'rounding trickery' so this method may or may not suit your requirements. It should be tested first with an approximate range of values that your implementation expects to determine if this approach is appropriate.

Check to see if UITextField has a numeric value greater than 0

I have a UITextField and I only want a number greater than 0 ( I don't want non-numeric characters or the value 0 )
This is how I check to see if it is empty:
if(seizure.text.length==0)
This is how I check to see if it is equal to 0:
else if(seizure.text doubleValue]==0)
How can I check for non-numeric characters?
First check to see if you have any characters in the string, then check to make sure that it only contains numeric characters, and finally check to see if the value is greater than 0:
if (seizure.text.length > 0)
{
NSCharacterSet *nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([seizure.text rangeOfCharacterFromSet:nonNumbers].location == NSNotFound)
{
if ([seizure.text doubleValue] > 0)
{
// Text Field contains a numeric value greater than 0
NSLog(#"Good number.");
return;
}
}
}
// If we make it to here, it does not meet your requirements.
NSLog(#"Bad Number.");
NSScanner will do the job nicely here. Unlike -[NSString doubleValue], its scanDouble: can parse and then also tell you whether it consumed the entire string, so you will know that there are non-numerical characters present.
Demonstration on some test cases. See the comments for descriptions of the expected results.
NSArray * texts = #[// First four unacceptable because non-numeric
#"", #"Hello, world!", #"1.0 excelsior", #"Jiminy 1.0 Crickets",
// These three unacceptable because 0 or less
#"0.0" #"0", #"-2048",
// Last three are good
#"3.14159", #"1", #"10000000000.0"];
for( NSString * text in texts ){
NSScanner * scanner = [NSScanner scannerWithString:text];
double val;
[scanner scanDouble:&val];
// Scanned the whole string and ended up with a positive value
if( [scanner isAtEnd] && val > 0 ){
NSLog(#"'%#'? I accept.", text);
}
else {
NSLog(#"'%#' is no good.", text);
}
}
[seizure.text doubleValue] == 0 will be true either if seizure.text is a textual representation of zero or if it doesn't contain a valid textual representation of a number (see the documentation for doubleValue).
In other words if this expression is false then you have a string value which starts with a number. However you still don't know if you string value contains only a number, e.g. [#"2.5 miles" doubleValue] has the value 2.5. If you need to handle strings like this you should look at NSScanner.

NSString's method 'getCString' return false for Arabic text

I am generating QR code and everything is working fine if text is only in English. When i want to generate QR code with some Arabic text then it fails at NSString's method "getCString:maxLength:encoding:".
Suppose, I have two strings:
NSString *englishText = #"Some text English";
NSString *englishArabicMixText = #"Some text بالعربي";
char strEng [[englishText length] + 1];
char strArb [[englishArabicMixText length] + 1];
1- [englishText getCString:strEng maxLength:[englishText length] + 1 encoding:NSUTF8StringEncoding];
2- [englishArabicMixText getCString:strArb maxLength:[englishArabicMixText length] + 1 encoding:NSUTF8StringEncoding];
At Case#1 'getCString' return true and QR code is generated and at Case#2 it return false and failed to generate code.
What should I do, so that in case#2 it should also return true ? Thank you
length returns the number of Unicode characters. You have to use lengthOfBytesUsingEncoding:, which returns the number of bytes required to store the receiver in a given encoding.
NSUInteger arbLength = [englishArabicMixText lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
char strArb [arbLength];
[englishArabicMixText getCString:strArb maxLength:arbLength encoding:NSUTF8StringEncoding];
2 is returning false for either 2 possible reasons:
1) the string cannot be converted with the specified encoding.
2) the buffer to hold the encoded string is too small.
I'd guess (or at least I suggest you to start investigating) problem is nr. 2.
Because as you're converting to UTF8 a single un-encoded character may result in more than one encoded character. An 'A' is a single byte with value 65 but an arabic character or some kind of symbol may require more bytes.
You are assuming your destination buffer requires the same number of bytes as the same number of characters of your NSString
So you should do something like that:
NSUInteger size = [englishArabicMixText lengthOfBytesUsingEncoding : NSUTF8StringEncoding];
if(size>0)
{
size++;
strArb = malloc(size); // NOTE: you should allocate space for your string at runtime!!
[englishArabicMixText getCString:strArb maxLength:size encoding:NSUTF8StringEncoding];
}
You should do the same for the plain english string too.
And I'd reccomend to allocate dinamically at runtime the space for the C string with malloc and then free it when you don't need it anymore.

Resources