views:

401

answers:

1

Hi everyone, I have an array with french strings let say: "égrener" and "exact" I would like to sort it such as égrener is the first. When I do:

NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:descriptor];
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];

I get the é at the end of the list... What should I do?

Thanks

+3  A: 

There’s a convenience method in NSString that lets you do this type of sorting easily:

NSArray *sortedArray = [myArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

NSString’s underlying comparison method (compare:options:range:locale:) gives you even more options of how sorting should be done.

Edit: Here’s the long story:

First, define a comparison function. This one is good for natural string sorting:

static NSInteger comparator(id a, id b, void* context)
{
    NSInteger options = NSCaseInsensitiveSearch
        | NSNumericSearch              // Numbers are compared using numeric value
        | NSDiacriticInsensitiveSearch // Ignores diacritics (â == á == a)
        | NSWidthInsensitiveSearch;    // Unicode special width is ignored

    return [(NSString*)a compare:b options:options];
}

Then, sort the array.

    NSArray* myArray = [NSArray arrayWithObjects:@"foo_002", @"fôõ_1", @"fôõ_3", @"foo_0", @"foo_1.5", nil];
    NSArray* sortedArray = [myArray sortedArrayUsingFunction:comparator context:NULL];

The array in the example contains some funny characters: Numbers, diacritical marks, and some characters from unicode range ff00. The last character type looks like an ASCII character but is printed in a different width.

The used comparison function handles all cases in human predictable way. The sorted array has the following order:

foo_0
fôõ_1
foo_1.5
foo_002
fôõ_3
Nikolai Ruhe
thanks but I don't really understand how I can implement that and sort it by name?
ncohen
The key is the locale parameter. Your problem now is that the system locale is set to english. You need it set to French. You could just do it at the system or app level for a French app. If you just need to occasionally process French, you would pass the appropriate locale to the sort so the sort would now to use French instead of English sorting. Read up on localization in the Apple Docs. It sounds like you 'll be using it a lot.
TechZen
Don't get it... it is not a problem of localization... it is a problem of special characters in an array!
ncohen
As @ncohen says, it’s not about locale but about **options**. The comparison method I proposed uses a bunch of options which it passes to `compare:options:range:locale:`. I just proposed the `localizedCaseInsensitiveCompare` because that’s what most user expect of a lexicographical sort order and it’s quite handy to use. As I said, if you want to have more control about what the comparison method takes for equal, your should use the underlying `compare:options:range:locale:` method (You’d have to wrap it into a C function to use it for array sorting with `sortedArrayUsingFunction:context:`).
Nikolai Ruhe
B.t.w. The option in question is called `NSDiacriticInsensitiveSearch`.
Nikolai Ruhe
thanks! It is still not very clear but you gave me the beginning... I ll work on it.
ncohen