2012-05-21 4 views
3

Пожалуйста, обратите внимание на следующий код:Странная строка C и проблема сравнения NSString

NSString *string = @"ä"; 
const char *str1 = [string cStringUsingEncoding:NSUTF8StringEncoding]; 
const char *str2 = "ä"; 
NSLog(@"C string comparison: %d",strcmp(str1,str2)); 
NSLog(@"str1: \"%s\"", str1); 
NSLog(@"str2: \"%s\"", str2); 

Если работать с совершенно новым проектом Фонда, эта программа выводит:

C string comparison: 0 
str1: "ä" 
str2: "ä" 

Это действительно то, что я Ожидается, что произойдет, потому что строки должны быть одинаковыми.

Однако, если я бегу это точно такой же код где-то глубоко внутри другого кодовую, я получаю этот выход:

C string comparison: 31 
str1: "ä" 
str2: "ä" 

Что может объяснить это различие? Я уверен, что оба файла находятся в кодировке UTF-8. Это - разные кодировки файлов - это единственное возможное объяснение этого поведения, верно?

Любые идеи, что могло бы пойти не так во втором случае? Как я могу это исправить?

(я должен упомянуть, пожалуй, что во втором случае код запущен в качестве .mm файла, т.е. в Objective-C++. Может ли это быть объяснение для этого?)

+0

Я бы попробовать войти какие строки фактически сравниваются во втором случае. – Marvo

+0

И убедитесь, что вы помещаете кавычки вокруг строк при их регистрации, чтобы убедиться, что у вас нет некоторого заднего пробела. – Marvo

+0

@Marvo Спасибо, я изменил свой вопрос соответственно. – meh

ответ

0

Как исходный файл закодирован на диске - это одно. Как считает компилятор , он кодируется. По умолчанию GCC предполагает UTF-8, но можно сказать, что он находится в другой кодировке из языкового стандарта или -finput-charset=<charset>. Я ожидаю, что Кланг поддерживает то же самое.

Xcode имеет собственное понятие кодирования исходного файла. Я не знаю, приспосабливает ли она команду компиляции передать это при использовании вышеуказанного параметра, но я не удивлюсь.

GCC также имеет понятие набора символов выполнения. Вот как он записывает строки в двоичный файл. См. Вариант -fexec-charset=<charset>.

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

Другая проблема заключается в том, что «ä» имеет два возможных представления в Unicode. Это может быть ЛАТИНСКАЯ МАЛЕНЬКАЯ ПИСЬМА A С ДИАЕРЕЗОМ (U + 00E4), или это может быть ЛАТИНСКАЯ МАЛЕНЬКАЯ ПИСЬМА A (U + 0061), а затем КОМБИНИРОВАННАЯ ДИАВЕРСИЯ (U + 0308). В UTF-8 это будет 0xC3 0xA4 против 0x61 0xCC 0x88. Ваши два исходных файла могут выражать один и тот же символ по-разному, что означает, что они действительно содержат разные строки (на всех уровнях: C string, NSString, независимо от того, хотя NSString проигнорирует эту разницу для методов -compare:..., если не указано NSLiteralSearch, методы -isEqual... буквальное сравнение, хотя). Это, конечно же, будет усугубляться, если эти два байтовых последовательностей будут преобразованы по кодировкам по-разному.

Итак, вам нужно отследить конкретные исходные файлы, содержащие соответствующие строки. Проверьте с шестнадцатеричным дампом, в котором содержится байт. Проверьте команды, используемые для их компиляции (и, возможно, среды, если язык может играть роль), чтобы увидеть, что компилятор считает, что вводятся и исполняемые наборы символов.

2

Вы можете попробовать использовать юникод версии ваших персонажей?

т.е.

NSString * string1 = @"\u00e4" ; 

ср http://blog.ablepear.com/2010/07/objective-c-tuesdays-unicode-string.html

+0

просто удар в темноте – nielsbot

+0

Кроме того, я предполагаю, что в 'NSLog' спецификатор формата% s ожидает ASCII, но вы передаете символы, отличные от ASCII. – nielsbot

+0

На самом деле я думаю, что я прав. См. Этот ответ: http://stackoverflow.com/a/722984/210171 – nielsbot

0

От Documentation:

Возвращенный строка C гарантированно будет действительна только до тех пор, либо приемник не будет освобожден, или пока текущий пул autorelease не опорожняется, зависимости от того, что наступит раньше.

Я думаю, что в вашем случае освобождается приемник или пул авторекламы пуст.
Например

NSString *string = @"ä"; 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
const char *str3 = [string cStringUsingEncoding:NSUTF8StringEncoding]; 
[pool release]; 
NSLog(@"str1: \"%s\"", str3); 
const char *str2 = "ä"; 
NSLog(@"C string comparison: %d",strcmp(str3,str2)); 
NSLog(@"str2: \"%s\"", str2); 

Выход

2012-05-22 17:14:50.069 test[32895:a0f] str1: "ä" 
2012-05-22 17:14:50.071 test[32895:a0f] C string comparison: -195 
2012-05-22 17:14:50.074 test[32895:a0f] str2: "ä" 



NSString *string = @"ä"; 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
const char *str3 = [string cStringUsingEncoding:NSUTF8StringEncoding]; 
[pool release]; 
const char *str2 = "ä"; 
NSLog(@"C string comparison: %d",strcmp(str3,str2)); 
NSLog(@"str1: \"%s\"", str3); 
NSLog(@"str2: \"%s\"", str2); 

Выход

2012-05-22 17:19:13.226 test[33153:a0f] C string comparison: 0 
2012-05-22 17:19:13.228 test[33153:a0f] str1: "" 
2012-05-22 17:19:13.229 test[33153:a0f] str2: "ä" 
Смежные вопросы