преобразование строки NSString с символами ударения в строку CString - PullRequest
5 голосов
/ 09 сентября 2011

У меня есть NSString со значением Хосе (акцент на е).Я пытаюсь преобразовать его в строку C следующим образом:

char str [[myAccentStr length] + 1];
[myAccentStr getCString:str maxLength:[myAccentStr length] + 1 encoding:NSUTF32StringEncoding];

, но str заканчивается пустой строкой.Что дает?Я пробовал UTF8 и UTF16 тоже.Позже она передается другой функции, и когда эта функция вызывает для нее lstrlen, размер становится равным нулю.

Ответы [ 2 ]

1 голос
/ 09 сентября 2011

[aString length] возвращает количество символов. В вашем случае это 4 .

Вы можете точно преобразовать вашу строку в строку c, используя, например, NSUTF8StringEncoding , NSUTF16StringEncoding , NSUTF32StringEncoding . Длина в байтах будет 5 , 8 , 16 соответственно.

NSString *myAccentStr = @"José";
NSUInteger l1 = [myAccentStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger l2 = [myAccentStr lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
NSUInteger l3 = [myAccentStr lengthOfBytesUsingEncoding:NSUTF32StringEncoding];
NSLog(@"%ld %ld %ld", (long)l1, (long)l2, (long)l3);

> 5, 8, 16

В целях конвертации вы должны использовать -maximumLengthOfBytesUsingEncoding вместо -lengthOfBytesUsingEncoding

Всегда проверяйте правильность преобразования с помощью -canBeConvertedToEncoding

Есть веские причины для использования NSString

1 голос
/ 09 сентября 2011

Документы для NSString getCString: maxLength: кодировка говорит:

Вы можете использовать canBeConvertedToEncoding: чтобы проверить, может ли быть строка без потерь конвертируется в кодировку. Если это не так, вы можете использовать dataUsingEncoding: allowLossyConversion: получить C-строку представление с использованием кодирования, допускающего некоторую потерю информации (примечание что данные, возвращаемые dataUsingEncoding: allowLossyConversion: is не строгая C-строка, так как она не имеет нулевого терминатора).

Использование метода NSString dataUsingEncoding: allowLossyConversion: делает свое дело. Вот пример кода:

NSString *myAccentStr = @"José";
char str[[myAccentStr length] + 1];

// NSString * to C String (char*)
NSData *strData = [myAccentStr dataUsingEncoding:NSMacOSRomanStringEncoding 
                                allowLossyConversion:YES];
memcpy(str, [strData bytes], [strData length] + 1);
str[[myAccentStr length]] = '\0';
NSLog(@"str (from NSString* to c string): %s", str);

// C String (char*) to NSString *   
NSString *newAccentStr = [NSString stringWithCString:str 
                                            encoding:NSMacOSRomanStringEncoding];
NSLog(@"newAccentStr (from c string to NSString*):  %@", newAccentStr);

Вывод этого NSLog:

str (от NSString * до c string): Хосе

newAccentStr (от строки c до строки NSString): Хосе

До сих пор я видел эту работу правильно только при использовании NSMacOSRomanStringEncoding.


Редактировать

Изменение этого вики сообщества. Пожалуйста, не стесняйтесь редактировать.

У hooleyhoop есть несколько замечательных моментов, поэтому я подумал, что постараюсь сделать код максимально подробным. Если я что-то упустил, пожалуйста, включите.

Также - Не уверен, почему [NSString canBeConvertedToEncoding:] возвращает YES, даже если функция [NSString getCString: maxLength: encoding:] определенно работает неправильно (как видно из выходных данных).

Вот некоторый код, помогающий проанализировать, что работает, а что нет:

// Define Block variable to tests out different encodings
void (^tryGetCStringUsingEncoding)(NSString*, NSStringEncoding) = ^(NSString* originalNSString, NSStringEncoding encoding) {
    NSLog(@"Trying to convert \"%@\" using encoding: 0x%X", originalNSString, encoding);
    BOOL canEncode = [originalNSString canBeConvertedToEncoding:encoding];
    if (!canEncode)
    {
        NSLog(@"    Can not encode \"%@\" using encoding %X", originalNSString, encoding);
    }
    else
    {
        // Try encoding using NSString getCString:maxLength:encoding:
        NSUInteger cStrLength = [originalNSString lengthOfBytesUsingEncoding:encoding];
        char cstr[cStrLength];
        [originalNSString getCString:cstr maxLength:cStrLength encoding:encoding];
        NSLog(@"    Converted(1): \"%s\"  (expected length: %u)",
              cstr, cStrLength);

        // Try encoding using NSString dataUsingEncoding:allowLossyConversion:          
        NSData *strData = [originalNSString dataUsingEncoding:encoding allowLossyConversion:YES];
        char cstr2[[strData length] + 1];
        memcpy(cstr2, [strData bytes], [strData length] + 1);
        cstr2[[strData length]] = '\0';
        NSLog(@"    Converted(2): \"%s\"  (expected length: %u)",
              cstr2, [strData length]);
    }
};

NSString *myAccentStr = @"José";

// Try out whatever encoding you want
tryGetCStringUsingEncoding(myAccentStr, NSUTF8StringEncoding);
tryGetCStringUsingEncoding(myAccentStr, NSUTF16StringEncoding);
tryGetCStringUsingEncoding(myAccentStr, NSUTF32StringEncoding);
tryGetCStringUsingEncoding(myAccentStr, NSMacOSRomanStringEncoding);

Результаты:

> Trying to convert "José" using encoding: 0x4
>     Converted(1): ""  (expected length: 5)
>     Converted(2): "José"  (expected length: 5)
> Trying to convert "José" using encoding: 0xA
>     Converted(1): ""  (expected length: 8)
>     Converted(2): "ˇ˛J"  (expected length: 10)
> Trying to convert "José" using encoding: 0x8C000100
>     Converted(1): ""  (expected length: 16)
>     Converted(2): "ˇ˛"  (expected length: 20)
> Trying to convert "José" using encoding: 0x1E
>     Converted(1): "-"  (expected length: 4)
>     Converted(2): "José"  (expected length: 4)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...