I am developing an iPhone application in objectiveC in which I have one array having alphanumeric, multilingual, special character data as shown below:
(
{
name = “#”;
},
{
name = “iPad”;
},
{
name = “عينة”;
},
{
name = “1”;
},
{
name = “أ”;
},
{
name = “10”;
},
)
Sorting should provide me result as below,
(
{
name = “iPad”;
},
{
name = “أ”;
},
{
name = “عينة”;
}
{
name = “#”;
},
{
name = “1”;
},
{
name = “10”;
},
)
Means first English and Arabic should be in alphabetical ascending order then special characters and then numbers in ascending order.
I got the solution using regular expression as below,
NSMutableArray *aMutArrArabic = [[NSMutableArray alloc] init];
for(NSDictionary *aDictObj in mutArrAddCard)
{
NSError *error = NULL;
NSRegularExpression *aRegexObj = [NSRegularExpression regularExpressionWithPattern:@"^[ء-ي]+$"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSArray *aArrMatches = [aRegexObj matchesInString:aDictObj[@"name"]
options:0
range:NSMakeRange(0, [aDictObj[@"name"] length])];
if([aArrMatches count] > 0)
{
[aMutArrArabic addObject:aDictObj];
}
}
This way I managed to get all arrays using their relevant regular expression.
There could be some improvement, by this is what you can do with sortedArrayUsingComparator:
and a custom comparator block.
Main idea:
- Get first char of the string.
- Determine what its "kind" (Letter, Arabic, Number, Other)
- Sort accordingly.
I started with these "kind":
typedef enum : NSUInteger {
CharacterOfKindArabic,
CharacterOfKindNumerical,
CharacterOfKindLetter,
CharacterOfKindOther
} CharacterOfKind;
And use this method to get the CharacterOfKind:
-(CharacterOfKind)retrieveFirstCharacterKindFromString:(NSString *)string
{
if ([string length])
{
unichar unicharacter = [string characterAtIndex:0];
if (unicharacter >= 0x600 && unicharacter <= 0x6ff)
return CharacterOfKindArabic;
if (unicharacter >= 0x750 && unicharacter <= 0x77f)
return CharacterOfKindArabic;
if (unicharacter >= 0xfb50 && unicharacter <= 0xfc3f)
return CharacterOfKindArabic;
if (unicharacter >= 0xfe70 && unicharacter <= 0xfefc)
return CharacterOfKindArabic;
NSString *firstChar = [string substringToIndex:1];
if ([firstChar rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet] options:0].location != NSNotFound)
return CharacterOfKindNumerical;
if ([firstChar rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet] options:0].location != NSNotFound)
return CharacterOfKindLetter;
return CharacterOfKindOther;
}
return CharacterOfKindOther;
}
I don't speak Arabic, and I never had to code with Arabic text. So I took these info of "character range" from the net. I read something on Objective-C here on StackOverflow, but I couldn't retrieve it. Maybe my memory is playing with me, but the range may have changed (more ranges added). I find the method a little ugly, but that's to get the main point.
NSString *kName = @"name";
NSArray *arrayToSort = @[@{kName:@"#"},
@{kName:@"iPhone"},
@{kName:@"iPad"},
@{kName:@"عينة"},
@{kName:@"1"},
@{kName:@"أ"},
@{kName:@"10"}];
NSLog(@"arrayToSort: %@", arrayToSort);
NSArray *typeSort = @[@(CharacterOfKindLetter), @(CharacterOfKindArabic), @(CharacterOfKindOther), @(CharacterOfKindNumerical)];
NSArray *sortedArray = [arrayToSort sortedArrayUsingComparator:^NSComparisonResult(NSDictionary * _Nonnull obj1, NSDictionary * _Nonnull obj2)
{
NSString *firstString = obj1[kName];
NSString *secondString = obj2[kName];
CharacterOfKind firstCharType = [self retrieveFirstCharacterKindFromString:firstString];
CharacterOfKind secondCharType = [self retrieveFirstCharacterKindFromString:secondString];
if (firstCharType == secondCharType) //Same Kind of first characters, do a normal "compare"
{
return [firstString compare:secondString];
}
else //Do a custom compare according typeSort
{
//Returns correctly according to the order set in typeSort
return [@([typeSort indexOfObject:@(firstCharType)]) compare:@([typeSort indexOfObject:@(secondCharType)])];
}
}];
NSLog(@"SortedArray: %@", sortedArray);
Output:
>>>arrayToSort: (
{
name = "#";
},
{
name = iPhone;
},
{
name = iPad;
},
{
name = "\U0639\U064a\U0646\U0629";
},
{
name = 1;
},
{
name = "\U0623";
},
{
name = 10;
}
)
>>>SortedArray: (
{
name = iPad;
},
{
name = iPhone;
},
{
name = "\U0623";
},
{
name = "\U0639\U064a\U0646\U0629";
},
{
name = "#";
},
{
name = 1;
},
{
name = 10;
}
)