I need to validate a password with these rules:
Password must have 6-12 characters
and at least two of the following:
Uppercase letters, Lowercase letters, Numbers or Symbols.
Below is my current regex:
^((?=.*[a-z])|(?=.*[A-Z])|(?=.*\\d)|(?=.*(_|[-+_!##$%^&*.,?]))).{6,12}
I am struggling about how to make the 'at least' condition.
You may define a function to check your requirements one by one and increment a counter to see how many of them actually are met. If more than 1 matched and the string length is between 6 and 12, the password passes.
NSUInteger checkPassword(NSString * haystack) {
NSArray * arr = [NSArray arrayWithObjects: #"(?s).*\\d.*", #"(?s).*[a-z].*", #"(?s).*[A-Z].*", #"(?s).*[-+_!##$%^&*.,?].*",nil];
NSUInteger cnt = 0;
for (NSUInteger index = 0; index < [arr count]; ++index) {
NSPredicate * passTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", [arr objectAtIndex:index]];
if ([passTest evaluateWithObject:haystack]) {
cnt = cnt + 1;
}
}
if (cnt > 1 && [haystack length] > 5 && [haystack length] < 13)
{
return 1;
}
else
{
return 0;
}
}
And a sample IDEONE demo:
NSString * s = #"123DF4ffg";
NSLog(#"Result: %d", checkPassword(s));
// => Result: 1
Note that it is possible to write a single pattern for this, but it will be rather long and clumsy as you need to define all possible pairs of lookahead alternatives.
you can try with this
^(?:(?=.*[a-z])(?:(?=.*[A-Z])(?=.*[\\d\\w])|(?=.*\\w)(?=.*\\d))|(?=.*\\w)(?=.*[A-Z])(?=.*\\d)).{6,12}$;
Related
I am making a game that requires me to use very large numbers. I believe I am able to store very large numbers with NSDecimal. However, when displaying the numbers to users I would like to be able to convert the large number to a succinct string that uses characters to signify the value eg. 100,000 -> 100k 1,000,000 -> 1.00M 4,200,000,000 -> 4.20B and so forth going up to extremely large numbers. Is there any built in method for doing so or would I have to use a bunch of
NSDecimalCompare statements to determine the size of the number and convert?
I am hoping to use objective c for the application.
I know that I can use NSString *string = NSDecimalString(&NSDecimal, _usLocale); to convert to a string could I then do some type of comparison on this string to get the result I'm looking for?
Use this method to convert your number into a smaller format just as you need:
-(NSString*) suffixNumber:(NSNumber*)number
{
if (!number)
return #"";
long long num = [number longLongValue];
int s = ( (num < 0) ? -1 : (num > 0) ? 1 : 0 );
NSString* sign = (s == -1 ? #"-" : #"" );
num = llabs(num);
if (num < 1000)
return [NSString stringWithFormat:#"%#%lld",sign,num];
int exp = (int) (log(num) / 3.f); //log(1000));
NSArray* units = #[#"K",#"M",#"G",#"T",#"P",#"E"];
return [NSString stringWithFormat:#"%#%.1f%#",sign, (num / pow(1000, exp)), [units objectAtIndex:(exp-1)]];
}
Some sample examples:
NSLog(#"%#",[self suffixNumber:#99999]); // 100.0K
NSLog(#"%#",[self suffixNumber:#5109999]); // 5.1M
Source
Solved my issue: Can only be used if you know that your NSDecimal that you are trying to format will only be a whole number without decimals so make sure you round when doing any math on the NSDecimals.
-(NSString *)returnFormattedString:(NSDecimal)nsDecimalToFormat{
NSMutableArray *formatArray = [NSMutableArray arrayWithObjects:#"%.2f",#"%.1f",#"%.0f",nil];
NSMutableArray *suffixes = [NSMutableArray arrayWithObjects:#"k",#"M",#"B",#"T",#"Qa",#"Qi",#"Sx",#"Sp",#"Oc",#"No",#"De",#"Ud",#"Dud",#"Tde",#"Qde",#"Qid",#"Sxd",#"Spd",#"Ocd",#"Nvd",#"Vi",#"Uvi",#"Dvi",#"Tvi", nil];
int dick = [suffixes count];
NSLog(#"count %i",dick);
NSString *string = NSDecimalString(&nsDecimalToFormat, _usLocale);
NSString *formatedString;
NSUInteger characterCount = [string length];
if (characterCount > 3) {
NSString *trimmedString=[string substringToIndex:3];
float a;
a = 100.00/(pow(10, (characterCount - 4)%3));
int remainder = (characterCount-4)%3;
int suffixIndex = (characterCount + 3 - 1)/3 - 2;
NSLog(#"%i",suffixIndex);
if(suffixIndex < [suffixes count]){
NSString *formatSpecifier = [formatArray[remainder] stringByAppendingString:suffixes[suffixIndex]];
formatedString= [NSString stringWithFormat:formatSpecifier, [trimmedString floatValue] / a];
}
else {
formatedString = #"too Big";
}
}
else{
formatedString = string;
}
return formatedString;
}
I have three mutable array:
wkdatearray values like this: date from 2016-01-10 to 2016-01-16.
spentonarray values like this: 2016-01-10 to 2016-01-13.
hoursarray values like this: 7,3,4,5,1.
So, I compare the index objects of wkdatearray and spentarray like this:
for (int i = 0; i < self.wkDateArray.count; i++) {
for (int j = 0; j < self.spentonArray.count; j++) {
if ([
[self.wkDateArray objectAtIndex: i] isEqualToString: [self.spentonArray objectAtIndex: j]
]) {
NSLog(# "Matched Indexes %d %#", i, [self.wkDateArray objectAtIndex: i]);
} else {
}
}
Now I want to get the result like :
If the index value of self.wkdatearray and self.spentonarray are matched or equals then I have to set the hours array value as object for self.wkdatearray[0],[1]…[6]. like this in newsheet dictionary. Now I manually put string #"".
newSheet = [NSDictionarydictionaryWithObjectsAndKeys:strEntryID,entryID, proj,project,projID,projectId, strIssue,issue,strIssueID,issueId, strActivity,activity,strActivityId,activityId,#"",comment,#"",self.wkDateArray[0],#"",self.wkDateArray[1],#"",self.wkDateArray[2],#"",self.wkDateArray[3],#"",self.wkDateArray[4],#"",self.wkDateArray[5],#"",self.wkDateArray[6], nil];
If the index value of self.wkdatearray and self.spentonarray are not matched and not equals then the hours value like this #“‘ as object for self.wkdatearray[0].like this in newsheet dictionary. Now, I put by default object values as #""for self.wkdatearray[0...6].
Here the hours array having 5 values only.
How to do both the conditions inside the for loop? Or is there any other way to do this?
First of all make the newSheet dictionary mutable. You do not need 2 for loops.
int minIndexCount = MIN(self.wkdatearray.count, self. spentonArray.count)
we first take the min of wkdatearray.count and spentonArray.count since for example if there are only 2 items in spentonArray then if we try to use index 4 of wkdatearray then we do not have index 4 in spentonArray, meaning the primary condition that the indexes of both wkdatearray and spentonArray should be equal fails. Hence by taking min we ensure that we are only going to compare those indexes whixha re available in both wkdatearray and spentonArray.
for (int i = 0; i < minIndexCount; i++) {
if ([[self.wkDateArray objectAtIndex: i] isEqualToString: [self.spentonArray objectAtIndex: i]])
{
NSLog(# "Matched Indexes %d %#", i, [self.wkDateArray objectAt Index: i]);
[newSheet setValue:self.hoursarray[i] forKey:self.weekArray[i]]
} else {
}
}
If by "matched or equals" you mean that if the index's are the same AND the strings are matched.
for (int i = 0; i < self.wkDateArray.count; i++) {
for (int j = 0; j < self.spentonArray.count; j++) {
if (i==j && [
[self.wkDateArray objectAtIndex: i] isEqualToString: [self.spentonArray objectAtIndex: j]
]) {
NSLog(# "Matched Indexes %d %#", i, [self.wkDateArray objectAtIndex: i]);
} else {
}
}
Take note of the beginning of the if statement that has if (i==j && ...
I'm building my own alternative to the Levenshtein distance to train myself in objective-c. This class will get a few sentences, only 2 during initial testing and return how many percent correct the sentence is. How many percent matches with the "correct sentence".
Basically what it does is it gets 2 sentences, (only 2 words during initial testing really) and calculates. But I get some strange NSLog's.
If I enter 1989 and 199 it'll return 75% correct - which is the correct answer. However, if I enter "orange" and "oange" - it returns 50% correct when correct is 83% (right??)
This is the code calling the method:
-(void)compare {
// Take each and every sentence from the users source and check it against the other sources. If it contains 2 or more words/numbers that are equal, i'll get "investigated" further
NSMutableArray *userSentences = [[MyManager sharedManager] contentSentencesList];
NSMutableArray *serverSentences = [NSMutableArray arrayWithArray:getSentencesFromText(serverText)];
// Sample sentences
[userSentences insertObject:#"oange" atIndex:userSentences.count];
[serverSentences insertObject:#"orange" atIndex:serverSentences.count];
// For-statement integers
int i = 0;
int b = 0;
for (i = 0; i < userSentences.count; i++) {
// Check first sentence
NSString *userSentence;
NSString *serverSentence;
// Check similarity of the two sentences, get percent and add to centerPercent
for (b = 0; b < serverSentences.count; b++) {
// Compare sentences
userSentence = userSentences[i];
serverSentence = serverSentences[b];
// Compare sentences with custom class
// Initialize Distance class
SourcerDistance *wordDistance = [[SourcerDistance alloc] init];
// Create resultPercent integer and calculate it
int resultPercent = [wordDistance distanceBetween:userSentence serverSentence:serverSentence];
NSLog(#"%#%d", #"FinishViewController result: ", resultPercent);
// Add resultPercent to averagePrecent and increase averagPercentToDivide by 1
centerPercent = centerPercent + resultPercent;
centerPercentToDivide++;
}
// Set and display resultoppositeSpelling
// averagePercent = centerPercent / centerPercentToDivide;
// Use an integer to remove decimals
[self presentResult];
}
}
and this is the other class:
#import "SourcerDistance.h"
#implementation SourcerDistance
-(int)distanceBetween:(NSString *)userSentence serverSentence:(NSString *)serverSentence {
// Declare the 2 arrays containing all the words from the user's source and the developer's source
NSArray *developerSourceSentence = [self getWords:serverSentence];
NSArray *userSourceSentence = [self getWords:userSentence];
// Declare variables that'll be use for for-statements
int developerWordsLoop = developerSourceSentence.count;
int userWordsLoop = userSourceSentence.count;
// Declare variables required for matching (average of all words)
float centerPercent = 0; // This is for ALL words in total
float centerPercentToDivide = 0; // This is for all words in total
// Single-word variables
float totalCharacters = 0;
float matchingCharacters = 0;
float percentMatchingSingleWord = 0;
NSLog(#"%#%d", #"userSourceSentenceCount: ", userSourceSentence.count);
NSLog(#"%#%d", #"developerSourceSentenceCount: ", developerSourceSentence.count);
// Loop through all of the user words
for (userWordsLoop = 0; userWordsLoop < userSourceSentence.count; userWordsLoop++) {
// Loop through all of the developer words
for (developerWordsLoop = 0; developerWordsLoop < developerSourceSentence.count; developerWordsLoop++) {
// Declare variables that contain all the characters of the user- and developer-words
NSMutableArray *userCharacters = [self getCharacters:userSourceSentence[userWordsLoop]];
NSMutableArray *developerCharacters = [self getCharacters:developerSourceSentence[developerWordsLoop]];
// Compare characters
matchingCharacters = [self compareCharacters:userCharacters developerCharacters:developerCharacters];
// Set the variables
totalCharacters = developerCharacters.count;
percentMatchingSingleWord = matchingCharacters / totalCharacters * 100;
NSLog(#"%#%f", #"totalCharacters", totalCharacters);
NSLog(#"%#%f", #"matchingCharacters", matchingCharacters);
NSLog(#"%#%f", #"iterate", percentMatchingSingleWord);
centerPercent = centerPercent + percentMatchingSingleWord;
centerPercentToDivide++;
}
}
// Declare variables used with final result
float finalPercentFloat = 0;
int finalPercent = 0;
NSLog(#"%#%f", #"centerPercent: ", centerPercent);
NSLog(#"%#%f", #"centerPercentToDivide: ", centerPercentToDivide);
finalPercentFloat = centerPercent/centerPercentToDivide;
NSLog(#"%#%f", #"finalPercent: ", finalPercentFloat);
finalPercent = (int)finalPercentFloat;
return finalPercent;
}
-(float)compareCharacters:(NSMutableArray *)userCharacters developerCharacters:(NSMutableArray *)developerCharacters {
// Declare result variables and other required variables
float matchingCharacters;
int userCharactersLoop = 0;
int developerCharactersLoop = 0;
// Loop through all of the userCharacters
for (userCharactersLoop = 0; userCharactersLoop < userCharacters.count; userCharactersLoop++) {
// Loop through all of the developerCharacters
for (developerCharactersLoop = 0; developerCharactersLoop < developerCharacters.count; developerCharactersLoop++) {
// Match every character here
if ([userCharacters[userCharactersLoop] isEqualToString:developerCharacters[developerCharactersLoop]]) {
// Increase matchingCharacters
matchingCharacters++;
} else {
// Do nothing
}
}
}
// Return result variable
return matchingCharacters;
}
-(NSArray *)getWords:(NSString *)sentence {
// Get words of sentence from developer-source
NSArray *sentenceWords;
NSString *serverSentenceToRead = sentence;
sentenceWords = [serverSentenceToRead componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#":;.!? "]
];
// Return developer words
return sentenceWords;
}
-(NSMutableArray *)getCharacters:(NSString *)word {
NSMutableArray *wordCharacters = [[NSMutableArray alloc] initWithCapacity:[word length]];
for (int i=0; i < [word length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%c", [word characterAtIndex:i]];
[wordCharacters addObject:ichar];
}
// Return the characters of the word
return wordCharacters;
}
#end
NSLog:
2014-09-03 20:22:32.015 Sourcer[27532:60b] userSourceSentenceCount: 1
2014-09-03 20:22:32.017 Sourcer[27532:60b] developerSourceSentenceCount: 1
2014-09-03 20:22:32.018 Sourcer[27532:60b] totalCharacters6.000000
2014-09-03 20:22:32.018 Sourcer[27532:60b] matchingCharacters3.001519
2014-09-03 20:22:32.019 Sourcer[27532:60b] iterate50.025322
2014-09-03 20:22:32.020 Sourcer[27532:60b] centerPercent: 50.025322
2014-09-03 20:22:32.021 Sourcer[27532:60b] centerPercentToDivide: 1.000000
2014-09-03 20:22:32.021 Sourcer[27532:60b] finalPercent: 50.025322
2014-09-03 20:22:32.022 Sourcer[27532:60b] FinishViewController result: 50
2014-09-03 20:22:32.022 Sourcer[27532:60b] averagePercent (float): 50.000000
What am I doing wrong here? Is it possible for anyone to understand the code and help me find out what's wrong? There's something odd about this algorithm
Thanks a lot!
(I know I'm kinda reinventing the wheel, but I want to try :))
Sincerely,
Erik
I have a sorted array of times like so
[0.0, 1.2, 4.3, 5.9, 7.2, 8.0]
While an audio file plays, I want to be able to take the current time and find what the nearest, lower number is in the array.
My approach would be to traverse the array, possible in reverse order as it feels like it should be faster. Is there a better way?
The playback SHOULD be linear, but might be fast-forwarded/rewound, so I would like to come up with a solution that takes that into account, but I'm not really sure how else to approach the problem.
The method you are looking for is -[NSArray indexOfObject:inSortedRange:options:usingComparator:]. It performs a binary search. With the options:NSBinarySearchingInsertionIndex option, if the value isn't found exactly, it returns the index where the object would be inserted, which is the index of the least larger element, or the count of items in the array.
NSTimeInterval currentTime = ...;
NSUInteger index = [times indexOfObject:#(currentTime)
inSortedRange:NSMakeRange(0, times.count)
options:NSBinarySearchingInsertionIndex
usingComparator:^(id object0, id object1) {
NSTimeInterval time0 = [object0 doubleValue];
NSTimeInterval time1 = [object1 doubleValue];
if (time0 < time1) return NSOrderedAscending;
else if (time0 > time1) return NSOrderedDescending;
else return NSOrderedSame;
}];
// If currentTime was not found exactly, then index is the next larger element
// or array count..
if (index == times.count || [times[index] doubleValue] > currentTime) {
--index;
}
The fastest* way to find something in a sorted array is binary search: if there are n items, check the element at index n/2. If that element is greater than what you're looking for, check the element at index n/4; otherwise, if it's less than what you're looking for, check the element at index 3n/4. Continue subdividing in this fashion until you've found what you want, i.e. the position where the current time should be. Then you can pick the preceding element, as that's the closest element that's less than the current time.
However, once you've done that once, you can keep track of where you are in the list. As the user plays through the file, keep checking to see if the time has passed the next element and so on. In other words, remember where you were, and use that when you check again. If the user rewinds, check the preceding elements.
*Arguably, this isn't strictly true -- there are surely faster ways if you can make a good guess as to the probable location of the element in question. But if you don't know anything other than that the element appears somewhere in the array, it's usually the right approach.
I'm not sure if it's the best approach, but I think it'll get the job done (assuming your array is always ascending order).
- (NSNumber *) incrementalClosestLowestNumberForNumber:(NSNumber *)aNumber inArray:(NSArray *)array {
for (int i = 0; i < array.count; i++) {
if ([array[i] floatValue] == [aNumber floatValue]) {
return aNumber;
}
else if ([array[i] floatValue] > [aNumber floatValue]) {
int index = (i > 0) ? i - 1 : 0;
return array[index];
}
}
return #0;
}
Then call it like this:
NSArray * numbArray = #[#0.0, #1.2, #4.3, #5.9, #7.2, #8.0];
NSNumber * closestNumber = [self closestLowestNumberForNumber:#2.4 inArray:numbArray];
NSLog(#"closest number: %#", closestNumber);
I'm not sure if someone else knows a special way that is much faster.
Based on some of the other answers / comments, I came up with this, perhaps one of them can point out if a whole is somewhere.
- (NSNumber *) quartalClosestLowestNumberForNumber:(NSNumber *)compareNumber inArray:(NSArray *)array {
int low = 0;
int high = array.count - 1;
NSNumber * lastNumber;
int currentIndex = 0;
for (currentIndex = low + (high - low) / 2; low <= high; currentIndex = low + (high - low) / 2) {
NSNumber * numb = array[currentIndex];
if (numb.floatValue < compareNumber.floatValue) {
low = currentIndex + 1;
}
else if (numb.floatValue > compareNumber.floatValue) {
high = currentIndex - 1;
}
else if (numb.floatValue == compareNumber.floatValue) {
return numb;
}
lastNumber = numb;
}
if (lastNumber.floatValue > compareNumber.floatValue && currentIndex != 0) {
lastNumber = array[currentIndex - 1];
}
return lastNumber;
}
I'm really bored right now, so I'm trying to test the fastest method. Here's how I did it.
NSMutableArray * numbersArray = [NSMutableArray new];
for (int i = 0; i < 100000; i++) {
float floater = i / 100.0;
[numbersArray addObject: #(floater)];
}
// courtesy #RobMayoff
NSDate * binaryDate = [NSDate date];
NSNumber * closestNumberBinary = [self binaryClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number binary: %# in: %f seconds", closestNumberBinary, -[binaryDate timeIntervalSinceNow]);
// The Quartal Version
NSDate * quartalDate = [NSDate date];
NSNumber * closestNumberQuartal = [self quartalClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number quartal: %# in: %f seconds", closestNumberQuartal, -[quartalDate timeIntervalSinceNow]);
// The incremental version
NSDate * incrementalDate = [NSDate date];
NSNumber * closestNumberIncremental = [self incrementalClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number incremental: %# in: %f seconds", closestNumberIncremental, -[incrementalDate timeIntervalSinceNow]);
And here's the output:
Found closest number binary: 4.4 in: 0.000030 seconds
Found closest number quartal: 4.4 in: 0.000015 seconds
Found closest number incremental: 4.4 in: 0.000092 seconds
And another test case:
Found closest number binary: 751.48 in: 0.000030 seconds
Found closest number quartal: 751.48 in: 0.000016 seconds
Found closest number incremental: 751.48 in: 0.013042 seconds
I have some data in an NSString, separated by colons:
#"John:Doe:1970:Male:Dodge:Durango"
I need to limit the total length of this string to 100 characters. But I also need to ensure the correct number of colons are present.
What would be a reasonable to way to truncate the string but also add the extra colons so I can parse it into the correct number of fields on the other side?
For example, if my limit was 18, you would end up with something like this:
#"John:Doe:1970:Ma::"
Here's an updated version of my own latest pass at this. Uses #blinkenlights algorithm:
+ (NSUInteger)occurrencesOfSubstring:(NSString *)substring inString:(NSString *)string {
// http://stackoverflow.com/a/5310084/878969
return [string length] - [[string stringByReplacingOccurrencesOfString:substring withString:#""] length] / [substring length];
}
+ (NSString *)truncateString:(NSString *)string toLength:(NSUInteger)length butKeepDelmiter:(NSString *)delimiter {
if (string.length <= length)
return string;
NSAssert(delimiter.length == 1, #"Expected delimiter to be a string containing a single character");
int numDelimitersInOriginal = [[self class] occurrencesOfSubstring:delimiter inString:string];
NSMutableString *truncatedString = [[string substringToIndex:length] mutableCopy];
int numDelimitersInTruncated = [[self class] occurrencesOfSubstring:delimiter inString:truncatedString];
int numDelimitersToAdd = numDelimitersInOriginal - numDelimitersInTruncated;
int index = length - 1;
while (numDelimitersToAdd > 0) { // edge case not handled here
NSRange nextRange = NSMakeRange(index, 1);
index -= 1;
NSString *rangeSubstring = [truncatedString substringWithRange:nextRange];
if ([rangeSubstring isEqualToString:delimiter])
continue;
[truncatedString replaceCharactersInRange:nextRange withString:delimiter];
numDelimitersToAdd -= 1;
}
return truncatedString;
}
Note that I don't think this solution handles the edge case from CRD where the number of delimiters is less than the limit.
The reason I need the correct number of colons is the code on the server will split on colon and expect to get 5 strings back.
You can assume the components of the colon separated string do not themselves contain colons.
Your current algorithm will not produce the correct result when one or more of the characters among the last colonsToAdd is a colon.
You can use this approach instead:
Cut the string at 100 characters, and store the characters in an NSMutableString
Count the number of colons, and subtract that number from the number that you need
Starting at the back of the string, replace non-colon characters with colons until you have the right number of colons.
I tend towards #dasblinkenlight, it's just an algorithm after all, but here's some code. Few modern shorthands - used an old compiler. ARC assumed. Won't claim it's efficient, or beautiful, but it does work and handles edge cases (repeated colons, too many fields for limit):
- (NSString *)abbreviate:(NSString *)input limit:(NSUInteger)limit
{
NSMutableArray *fields = [[input componentsSeparatedByString:#":"] mutableCopy];
NSUInteger colonCount = fields.count - 1;
if (colonCount >= limit)
return [#"" stringByPaddingToLength:limit withString:#":" startingAtIndex:0];
NSUInteger nonColonsRemaining = limit - colonCount;
for (NSUInteger ix = 0; ix <= colonCount; ix++)
{
if (nonColonsRemaining > 0)
{
NSString *fieldValue = [fields objectAtIndex:ix];
NSUInteger fieldLength = fieldValue.length;
if (fieldLength <= nonColonsRemaining)
nonColonsRemaining -= fieldLength;
else
{
[fields replaceObjectAtIndex:ix withObject:[fieldValue substringToIndex:nonColonsRemaining]];
nonColonsRemaining = 0;
}
}
else
[fields replaceObjectAtIndex:ix withObject:#""];
}
return [fields componentsJoinedByString:#":"];
}