Search through NSArray of objects with different locale - objective-c

I have an array of phone number objects, the phone number model is as follows:
#property NSString *hotlineName;
#property NSString *hotlineNameAr;
#property NSString *hotlineNumber;
#property NSString *hotlineImage;
#property NSInteger hotlineID;
#property RLMArray<Tags> *hotlineTags;
when I perform a search, I filter the array if either hotlineName, hotlineNameAr, hotlineNumber and in property hotlineTags: tagName and tagNameAr contain the search text.
I used NSPredicate to filter the array as such:
-(void) searchForText: (NSString *) searchText{
NSString *predicateFormat = #"SELF.%K contains[cd] %#";
NSString *tagFormat = #"ANY SELF.hotlineTags.%K contains[cd] %#";
NSString *searchNameAttribute = #"hotlineName" ;
NSString *searchTagAttribute = #"tagName";
NSString *searchNameAttribute_ar = #"hotlineNameAr" ;
NSString *searchTagAttribute_ar = #"tagNameAr";
NSString *numberAttribute = #"hotlineNumber";
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:predicateFormat, searchNameAttribute, searchText];
NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:tagFormat, searchTagAttribute, searchText];
NSPredicate *namePredicate_ar = [NSPredicate predicateWithFormat:predicateFormat, searchNameAttribute_ar, searchText];
NSPredicate *tagPredicate_ar = [NSPredicate predicateWithFormat:tagFormat, searchTagAttribute_ar, searchText];
NSPredicate *numberPredicate = [NSPredicate predicateWithFormat:predicateFormat, numberAttribute, searchText];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[namePredicate, numberPredicate, tagPredicate, namePredicate_ar, tagPredicate_ar]];
filteredResults = [hotlines_arr filteredArrayUsingPredicate:predicate];
}
and so far it works well, the problem arose when I search with numbers in a different locale, in this instance in Arabic, so used I NSNumberFormatter as such:
// Convert string From Arabic/Persian numbers to English numbers
+(NSString *) convertToEnglishNumber:(NSString *) string {
// NSNumericSearch
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"EN"];
[formatter setLocale:locale];
NSNumber *number = [formatter numberFromString:string];
return [number stringValue];
}
but the problem with NSNumberFormatter is that any leading zero's are ignored in the conversion, so I need an alternative to format the NSString based on locale or search array while taking in consideration locale, the same option in spotlight search.
I also tried formatting as such but it was in vain.
NSString *str = [[NSString alloc] initWithFormat:#"%#" locale:locale, searchText];
NSString *localizedString =[NSString localizedStringWithFormat:#"%#", searchText];

As I couldn't think of any other option and this was a last resort, I ended up replacing the string but I'm very unhappy with answer:
+ (NSString *) replaceStrings: (NSString *) textToEdit{
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"ar"];
for (NSInteger i= 0; i < 10; i++) {
NSString *stringVal = [#(i) stringValue];
NSString *localeString = [#(i) descriptionWithLocale:locale];
textToEdit = [textToEdit stringByReplacingOccurrencesOfString:localeString withString:stringVal];
}
return textToEdit;
}

Related

setting filter predicate in NSArrayController [duplicate]

I'm trying to prepare multiple search in my CoreData entity Recipes. There are parameters by which I would like to prepare fetch.
Recipes attributes:
#property (nonatomic, retain) NSNumber * difficulty;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSNumber * code; //like identifier
#property (nonatomic, retain) NSNumber * prepTime;
Ingredients is a separate entity with the list of ingredients.
Join entity contains ingredientCode, recipeCode, count.
getArrayOfJoinDataWithIngredients fetches join entity and returns NSArray of codes of recipes which contains some of input ingredient.
Here is my code:
- (IBAction)callRecipeFetch:(id)sender
{
NSString *predicateString = #"";
NSArray *codes = [[NSArray alloc] init]; codes = nil;
if ([paramController.ingredientsForSearchArray count] > 0) {
NSMutableArray *ingredientsArray = [[NSMutableArray alloc] init];
for (Ingredients *ingredient in paramController.ingredientsForSearchArray) {
[ingredientsArray addObject:ingredient.code];
}
MainTabController *mainTabController = [[MainTabController alloc] init];
codes = [mainTabController getArrayOfJoinDataWithIngredients:ingredientsArray];
NSString *ingrSet = [NSString stringWithFormat:#"(code IN %#)", codes];
predicateString = [predicateString stringByAppendingString:ingrSet];
}
NSString *diff;
if ([predicateString isEqualToString:#""]) {
diff = [NSString stringWithFormat:#"(difficulty <= %d)", paramController.diff.selectedSegmentIndex + 1];
}
else diff = [NSString stringWithFormat:#" AND (difficulty <= %d)", paramController.diff.selectedSegmentIndex + 1];
predicateString = [predicateString stringByAppendingString:diff];
NSString *timeString = [NSString stringWithFormat:#" AND (%d =< prepTime) AND (prepTime <= %d)", paramController.rangeSlider.leftValue, paramController.rangeSlider.rightValue];
predicateString = [predicateString stringByAppendingString:timeString];
if (paramController.categoryCode) {
NSString *categoryString = [NSString stringWithFormat:#" AND (inCategory = %#)", paramController.categoryCode];
predicateString = [predicateString stringByAppendingString:categoryString];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat: predicateString];
[resultController findRecipesWithPredicate:predicate];
}
The full predicateString is #"(code IN (\n 1,\n 3\n)) AND (difficulty <= 5) AND (0 =< prepTime) AND (prepTime <= 28800) AND (inCategory = 12)"
Now I have an error in predicate part (code IN %#) when I prepare NSPredicate with code:
NSPredicate *predicate = [NSPredicate predicateWithFormat: predicateString];
ERROR:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "(code IN (
1,
3
)) AND (difficulty <= 5) AND (0 =< prepTime) AND (prepTime <= 28800) AND (inCategory = 12)"'
How to correctly make predicate with IN operator. Thanks for all advices.
use NSCompoundPredicate for your multiple predicates, you can refer NSCompoundPredicate Class Reference
something like this:
NSPredicate * andPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:predicate1,predicate2,predicate3,nil]];
Addition to #Joshua's answer, you can also use NSCompoundPredicate for your OR operations like this.
Obj-C - OR
// OR Condition //
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:#"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicate1, predicate2]];
Swift - OR
let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2] )
Swift 3 - OR
let predicate1 = NSPredicate(format: "X == 1")
let predicate2 = NSPredicate(format: "Y == 2")
let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [predicate1,predicate2])
It will work for you.
NSPredicate *bPredicate;
bPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %# OR product_price contains[c] %# OR foodescription contains[c] %#",searchText,searchText,searchText];
NSArray *filteredArray = [getObjectsFromServiceArray filteredArrayUsingPredicate:bPredicate];

How to sum two elements of the array?

NSMutableArray *array = [NSMutableArray arrayWithObjects:#"22,343", #"44,323",#"34,5678",#"22,725", nil];
i have this array and I want to sum two values this array.
like this array[0] + array [1]
how to sum this elements?
thanks !!
Solution is
NSString *strVaue1 = [array[0] stringByReplacingOccurrencesOfString:#"," withString:#""];
NSString *strVaue2 = [array[1] stringByReplacingOccurrencesOfString:#"," withString:#""];
NSUInteger arrValue1 = [strVaue1 integerValue];
NSUInteger arrValue2 = [strVaue2 integerValue];
NSUInteger sum = arrValue1 + arrValue2;
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setNumberStyle:NSNumberFormatterDecimalStyle]; // to get commas (or locale equivalent)
[fmt setMaximumFractionDigits:0]; // to avoid any decimal
NSString *result = [fmt stringFromNumber:#(sum)];
NSLog(#"The result is - %#",result);
The printed result is
The result is - 66,666

search NSArray with regex

I have an array of names. If any of the name is already there then on inserting new name I want to append the counter eg John (02) if John already present in array then John (03) if it is third entry of name John.
Is there any way to filter array with Regex so that I can filter all records with pattern "John (xx)"?
Yup. You have to loop through the array and check with regex. You have to do this, since if you just check if the array contains your string, it won't return true if you search for "John" and the only one in your array is "John1"
NSMutableArray *testArray = [[NSMutableArray alloc] initWithObjects:#"John", #"Steve", #"Alan", #"Brad", nil];
NSString *nameToAdd = #"John";
NSString *regex = [NSString stringWithFormat:#"%#[,]*[0-9]*", nameToAdd];
NSPredicate *myTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
for (int i = 0; i < [testArray count]; i++)
{
NSString *string = [testArray objectAtIndex:i];
if ([myTest evaluateWithObject:string])
{
// Matches
NSLog(#" match !");
int currentValue;
NSArray *split = [string componentsSeparatedByString:#","];
if ([split count] == 1)
{
// Set to 2
currentValue = 2;
}
else
{
currentValue = [[split objectAtIndex:1] intValue];
currentValue++;
}
NSString *newString = [NSString stringWithFormat:#"%#,%d", nameToAdd, currentValue];
[testArray replaceObjectAtIndex:i withObject:newString];
}
}
for (NSString *string in testArray)
{
NSLog(#"%#", string);
}
This will replace "John" with "John,2", and if you search for "John" a third time it will replace it with "John,3".
Hope this helps
You can create a predicate for your regular expression and then filter the array using the predicate. Based on the count of the matches, you can update the new value being added as needed.
NSMutableArray *currentNames = ... // the current list of names
NSString *newName = ... // the new name to add
NSString *regex = [NSString stringWithFormat:#"%# \\([0-9]*\\)", newName];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
NSArray *matches = [currentNames filteredArrayUsingPredicate:filter];
if (matches.count) {
NSString *updatedName = [NSString stringWithFormat:#"%# (%02d)", newName, matches.count];
[currentNames addObject:updatedName];
} else {
[currentNames addObject:newName];
}
You can filer an array with NSPredicate. Not too familiar with regex, but the following seems okay:
NSArray *array = #[#"John (01)", #"John (02)", #"John XX"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES 'John [(]\\\\d{2}[)]'"];
NSArray *result = [array filteredArrayUsingPredicate:predicate];
NSLog( #"%#", result ); // Output John (01), John (02)

Filter array of custom objects with a dictionary property

I have an array that holds MyCustomObject objects.
MyCustomObject has 3 properties:
NSString *id;
NSString *name;
NSDictionary *phones;
How do I filter that array by the content of the "phones" property?
All I saw online is:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"phones CONTAINS[c] %#",textField.text];
self.filteredArray = [self.unfilteredArray filteredArrayUsingPredicate:predicate];
But it doesn't help me much...
Thanks
MyCustomObject *value = [[MyCustomObject alloc] init];
for(value in arrayname)
{
NSString *str = [value.phones objectForKey:#"key"];
NSRange r = [str rangeOfString:textField.text options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
NSLog(#"Match found");
}
}
self.filterArray = [self.unfilteredArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
MyCustomObject *obj = (MyCustomObject*)evaluatedObject;
return ([[[obj.phones objectForKey:#"key"] lowercaseString] rangeOfString:[textField.text lowercaseString]].location != NSNotFound );
}]];

NSTextfield and user inputted regex

Is there an easy way to take a user inputted NSString from an NSTextfield, and convert it to a valid objc regex?
I would like to escape all the '\' characters, but obviously not all the unneeded ones, i.e.... '\n', ' \xA9', '\r' etc....
for example this:
NSString *rejectString = #"^Steve\-Smi+.*+(\n)?"
needs to become this:
#"^Steve\\-Smi+.*+(\n)?"
I have ended up using NSPredicate instead, its much more user friendly:
NSArray *array = [NSArray arrayWithObjects: ojb1, obj2, obj3, obj4, nil];
NSMutableArray *filteredArray = [NSMutableArray new];
NSString *ignoreString = [ignoreStringTextfield stringValue];
for (NSString *name in array)
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NOT (SELF MATCHES %#)", ignoreString];
if ([predicate evaluateWithObject:name])
[filteredArray addObject:name];
}
return filteredArray;