Reputation: 3854
I would like to check if a NSString contains each digit possible (0-9) more then 5 times. I do not need to know which digit or how many times, I simply want it to return TRUE or False for whether any of the digits are contained more then 5 times in the string. I would like it to be as efficient as possible.
I have given it some thought and the long way of going about it would be to place all 10 digits (again 0-9) in an array and then loop through each digit comparing it to the string. If there are more than 5 matches within the string, place a flag that will return true.
Can anyone tell me if there is a "better" or more efficient way of going about this problem?
Thank you!
Upvotes: 1
Views: 1207
Reputation: 56625
This may not be the "best" way of doing things but it was the most fun way of doing it for me and it takes quite good advantage of Foundation using characters sets, counted sets and block based string enumeration.
// Your string
NSString *myString = @"he11o 12345 th1s 55 1s 5 very fun 55 1ndeed.";
// A set of all numeric characters
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
NSUInteger digitThreshold = 5;
// An emtpy counted set
NSCountedSet *numberOccurances = [NSCountedSet new];
// Loop over all the substrings as composed characters
// this will not have the same issues with e.g. Chinese characters as
// using a C string would. (Available since iOS 4)
[myString enumerateSubstringsInRange:NSMakeRange(0, myString.length)
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
// Check if substring is part of numeric set of characters
if ([substring rangeOfCharacterFromSet:numbers].location != NSNotFound) {
[numberOccurances addObject:substring];
// Check if that number has occurred more than 5 times
if ([numberOccurances countForObject:substring] > digitThreshold) {
*stop = YES;
// Do something here based on that fact
NSLog(@"%@ occured more than %d times", substring, digitThreshold);
}
}
}];
If you don't let it stop then it will continue to count the number of occurrences for all the digits in that string.
If you log the counted set is looks like this (number within square brackets are count):
<NSCountedSet: 0xa18d830> (3 [1], 1 [6], 4 [1], 2 [1], 5 [6])
Upvotes: 3
Reputation: 81868
This code tries to be as performant as possible.
BOOL checkDigits(NSString *string)
{
// get the raw UTF-16 code fragments, hopefully without a copy
const UniChar *characters = CFStringGetCharactersPtr((__bridge CFStringRef)string);
NSData *characterData = nil;
if (characters == NULL) {
characterData = [string dataUsingEncoding:NSUTF16StringEncoding];
characters = [characterData bytes];
}
// initialize 10 individual counters for digits
int digitCount[10] = {};
NSUInteger length = [string length];
// loop over the characters once
for (NSUInteger i = 0; i != length; ++i) {
UniChar c = characters[i];
// UTF-16 encodes ASCII digits as their values
if (c >= '0' && c <= '9') {
int idx = c - '0';
if (digitCount[idx] == 4)
return YES;
digitCount[idx] += 1;
}
}
// keep the NSData object alive until here
[characterData self];
return NO;
}
Upvotes: 2
Reputation: 5064
Use following code to check string contain 0-9 :
NSUInteger count = 0, length = [yourString length];
NSRange range = NSMakeRange(0, length);
while(range.location != NSNotFound)
{
range = [yourString rangeOfString: @"hello" options:0 range:range];
if(range.location != NSNotFound)
{
range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
count++;
}
}
Upvotes: 0
Reputation: 409
NSString *materialnumber =[[self.documentItemsArray objectAtIndex:indexPath.row] getMATERIAL_NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES '[0-9*]+'"];
if ([predicate evaluateWithObject:materialnumber])
{
materialnumber = [NSString stringWithFormat:@"%d",[materialnumber intValue]];
}
Upvotes: -1