【问题标题】:Convert NSString to C string, increment and come back to NSString将 NSString 转换为 C 字符串,递增并返回 NSString
【发布时间】:2011-10-02 09:27:45
【问题描述】:

我正在尝试开发一个可以加密消息的简单应用程序。该算法是 Caesar 算法,例如,对于“Hello World”,如果增量为 3(标准),则打印“KHOOR ZRUOG”。

我的问题是如何获取每个字符并增加它...

我试过了:

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 ' c' 我在控制台中看不到结果。问题出在哪里?

【问题讨论】:

    标签: objective-c c xcode ios4


    【解决方案1】:

    首先,逐字节递增仅适用于 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);
    

    【讨论】:

    • +1 虽然对于这个问题来说答案可能过于详尽。
    • 很好,谢谢!! :) 它工作得很好,在性能上也是如此!但是,它似乎只适用于大写单词,我们如何使用小写单词来改进呢?我试过在最后一个 if(buffer[i] > 'z') 中添加一个条件,但它不起作用......似乎它打印了它想要的任何东西......
    • xTuMiOx 是的,此代码假定您的字符串仅包含大写的 ASCII 字符。将 'Z' 替换为 'z' 使其 only 与小写 ASCII 字符串一起工作。要同时支持大写和小写,您需要对原始字符设置一个 if 条件,但这违背了凯撒密码的目的。当然,凯撒密码已经没有实际用途了,所以......
    【解决方案2】:

    首先用这个替换你的代码:

    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
    

    这意味着 NSString 命名字符串中的 char 'h' 值 @"h" 保存在内存中的地址 0x711DD10 处。

    现在我们将这个地址增加 3。下一个输出是这样的:

    Addr: 0x711DD13
    

    在我的例子中,这个地址有一个“0x00”。但实际上存在什么并不重要,因为“k”不会存在(除非你很幸运)。
    如果你很高兴,也有一个 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...
    }
    

    【讨论】:

    • 天啊,我忘了我正在使用指针!感谢您的建议和超级详细的帮助!它也可以完美地工作(对于其他用户),但我选择了另一个答案,因为它最适合我的需要,抱歉......
    猜你喜欢
    • 1970-01-01
    • 2013-12-12
    • 2015-11-22
    • 2015-11-30
    • 1970-01-01
    • 2013-12-08
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    相关资源
    最近更新 更多