Sorting array having special characters, numbers,

2019-09-11 07:27发布

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.

2条回答
我命由我不由天
2楼-- · 2019-09-11 07:28

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;
    }
)
查看更多
成全新的幸福
3楼-- · 2019-09-11 07:38

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.

查看更多
登录 后发表回答