Есть ли способ использовать NSString stringByFoldingWithOptions, чтобы развернуть один французский символ «œ» в «oe»?

Для функции полнотекстового поиска, не зависящей от диакритических знаков, я использую следующий код для преобразования символов с диакритическими знаками, таких как é или Ö, в их строчные формы без акцента e и o.

[[inputString stringByFoldingWithOptions: 
    NSCaseInsensitiveSearch
    + NSDiacriticInsensitiveSearch
    + NSWidthInsensitiveSearch
locale: [NSLocale currentLocale]] lowercaseString];

Это работает. Однако я не нашел способа преобразовать специальные символы, базовая форма которых состоит из нескольких символов, таких как французский œ (как в «sœur») или немецкий ß (как в «Fluß»). Я хотел бы преобразовать их в oe и ss соответственно. Я не нашел флага для stringByFoldingWithOptions и ничего не нашел в Интернете.

ИЗМЕНИТЬ

ß на самом деле правильно обрабатывается приведенным выше кодом. Он преобразуется в ss.


person regular    schedule 09.04.2012    source источник
comment
возможный дубликат NSString - как перейти от ÁlgeBra к алгебре   -  person Jack    schedule 10.04.2012
comment
Я не эксперт, но я -decomposedStringWithCompatibilityMapping делаю это для вас?   -  person joerick    schedule 10.04.2012
comment
œ не разлагается, к сожалению. :(   -  person Wevah    schedule 10.04.2012
comment
@Jack: на самом деле нет, ни один из представленных там методов не преобразует один символ в несколько символов. На самом деле код в окончательном ответе похож на код в моем вопросе.   -  person regular    schedule 10.04.2012
comment
@joerick: как указывает Вева, œ не обрабатывается -decomposedStringWithCompatibilityMapping   -  person regular    schedule 10.04.2012
comment
только что узнал: код в вопросе действительно правильно обрабатывает регистр ß (преобразовывает в ss)   -  person regular    schedule 10.04.2012
comment
У меня такая же проблема. Я считаю, что это также не работает с AE (Æ). Мне нужно, чтобы иметь возможность группировать текст под общим заголовком разделов A и O. Но у меня есть отдельные разделы для Æ и Œ. Я бы хотел, чтобы все слова, начинающиеся с Æ и Œ, попадали в разделы A и O соответственно.   -  person Tap Forms    schedule 21.10.2012


Ответы (2)


От худшего решения к лучшему.

Решение 1 будет работать только для æ и ß и не работает для всех остальных (œ, ij, , fi , , , , , , ...) :

NSString *result = [[[NSString alloc] initWithData:[inputString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] encoding:NSASCIIStringEncoding] autorelease];

Решение 2 будет работать для большинства лигатур и не работает только для æ, œ и ij. Я перепробовал все возможные NSLocale, так что проблема не в этом:

NSString *result = [inputString stringByFoldingWithOptions:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch locale:[NSLocale currentLocale]];

Решение 3 будет работать для большинства лигатур и не работает только для œ:

NSString *result = [[[NSString alloc] initWithData:[[inputString precomposedStringWithCompatibilityMapping] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] encoding:NSASCIIStringEncoding] autorelease];

Это означает, что œ всегда нужно будет обрабатывать вручную. И лучшее решение - объединить решение 2 или 3 с ручной заменой строки.

Решение 2бис:

inputString = [inputString stringByReplacingOccurrencesOfString:@"æ" withString:@"ae" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [inputString length])];
inputString = [inputString stringByReplacingOccurrencesOfString:@"œ" withString:@"oe" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [inputString length])];
inputString = [inputString stringByReplacingOccurrencesOfString:@"ij" withString:@"ij" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [inputString length])];
NSString *result = [inputString stringByFoldingWithOptions:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch locale:[NSLocale currentLocale]];

Решение 3bis:

inputString = [inputString stringByReplacingOccurrencesOfString:@"Œ" withString:@"OE"];
inputString = [inputString stringByReplacingOccurrencesOfString:@"œ" withString:@"oe"];
NSString *result = [[[NSString alloc] initWithData:[[inputString precomposedStringWithCompatibilityMapping] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] encoding:NSASCIIStringEncoding] autorelease];

Зная, что я могу пропустить некоторые замены с решением 2bis, а NSLocale непредсказуем, лучшим решением является 3bis. А также это последнее решение позволяет вам сохранять чувствительность к регистру, если вам нужно.

person Cœur    schedule 15.01.2014
comment
Я думаю, что лучшая часть этого решения заключается в том, что пользователь, предлагающий его, использует рассматриваемый символ в своем имени. - person dpassage; 15.01.2014
comment
Я думаю, что лучшая часть этого ответа заключается в том, что он действительно представляет решение! - person regular; 16.01.2014

Взгляните на CFStringTransform() и его вариант kCFStringTransformToLatin. Я думаю, что это может сделать то, что вы ищете.

person Ken Thomases    schedule 09.04.2012
comment
Я пробовал CFStringTransform(string, NULL, kCFStringTransformToLatin, FALSE); Возвращает 1, однако строка остается неизменной (sœur) - person regular; 10.04.2012
comment
то же самое для kCFStringTransformStripCombiningMarks - person regular; 10.04.2012