Конвертируйте NSString в строку C, увеличивайте ее и возвращайтесь к NSString - PullRequest
1 голос
/ 02 октября 2011

Я пытаюсь разработать простое приложение, где я могу зашифровать сообщение. Алгоритм является алгоритмом Цезаря и, например, для «Hello World» он печатает «KHOOR ZRUOG», если приращение равно 3 (стандартное).

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

Я пробовал это:

NSString *text = @"hello";
int q, increment = 3;
NSString *string;

for (q = 0; q < [text length]; q++) {

    string = [text substringWithRange:NSMakeRange(q, 1)];

    const char *c = [string UTF8String] + increment;
    NSLog(@"%@", [NSString stringWithUTF8String:c]);
}

очень просто, но это не работает .. Моя теория была такой: взять каждый отдельный символ, преобразовать его в строку c и увеличить его, затем вернуться к NSString и напечатать его, но xcode ничего не печатать, даже если я печатаю char ' Я не могу увидеть результат в консоли. Где проблема?

Ответы [ 2 ]

3 голосов
/ 02 октября 2011

Прежде всего, увеличение байта за байтом работает только для строк ASCII. Если вы используете UTF-8, вы получите мусор для глифов, которые имеют многобайтовые представления.

Имея это в виду, это должно работать (и работать быстрее, чем characterAtIndex: и подобные методы):

NSString *foo = @"FOOBAR";
int increment = 3;

NSUInteger bufferSize = [foo length] + 1;
char *buffer = (char *)calloc(bufferSize, sizeof(char));

if ([foo getCString:buffer maxLength:bufferSize encoding:NSASCIIStringEncoding]) {
    int bufferLen = strlen(buffer);
    for (int i = 0; i < bufferLen; i++) {
        buffer[i] += increment;
        if (buffer[i] > 'Z') {
            buffer[i] -= 26;
        }
    }

    NSString *encoded = [NSString stringWithCString:buffer 
                                           encoding:NSASCIIStringEncoding];
}
free(buffer);
2 голосов
/ 02 октября 2011

прежде всего замените ваш код следующим:

for (q = 0; q < [text length]; q++) {

    string = [text substringWithRange:NSMakeRange(q, 1)];

    const char *c = [string UTF8String];

    NSLog(@"Addr: 0x%X", c);
    c = c +  increment;
    NSLog(@"Addr: 0x%X", c);        

    NSLog(@"%@", [NSString stringWithUTF8String:c]);
}

Теперь вы можете выяснить вашу проблему. const char * c является указателем. Указатель сохраняет адрес памяти. Когда я запускаю этот код, первый вывод журнала выглядит так:

Addr: 0x711DD10

, что означает, что символ 'h' из именованной строки NSString со значением @ "h" сохраняется по адресу 0x711DD10 в памяти.

Теперь мы увеличиваем этот адрес на 3. Следующий вывод:

Addr: 0x711DD13

В моем случае по этому адресу есть «0x00». Но не имеет значения, что на самом деле там, потому что «к» там не будет (если вам не очень повезет).
Если вы счастливы, есть и 0x00. Потому что тогда ничего плохого не случится. Если вам не повезло, есть что-то еще. Если есть что-то отличное от 0x00 (или разделитель строк или «конец строки»), NSString попытается преобразовать это. При попытке этого может произойти сбой или может открыться огромная дыра в безопасности.


поэтому вместо манипулирования указателями вы должны манипулировать значениями, на которые они указывают.

Вы можете сделать это так:

for (q = 0; q < [text length]; q++) {

    string = [text substringWithRange:NSMakeRange(q, 1)];

    const char *c = [string UTF8String];    // get the pointer

    char character = *c;                    // get the character from this pointer address
    character = character + 3;              // add 3 to the letter

    char cString[2] = {0, 0};               // create a cstring with length of 1. The second char is \0, the delimiter (the "end marker") of the string
    cString[0] = character;                 // assign our changed character to the first character of the cstring

    NSLog(@"%@", [NSString stringWithUTF8String:cString]); // profit...
}
...