【问题标题】:Process unicode string in C and Objective C在 C 和 Objective C 中处理 unicode 字符串
【发布时间】:2014-06-14 18:18:09
【问题描述】:

我编写了一个 C 函数来读取用户输入字符串中的字符。因为这个字符串是用户输入的,所以它可以包含任何 unicode 字符。有一个Objective C 方法接收用户输入的NSString,然后将该字符串转换为NSData 并将该数据传递给C 函数进行处理。 C 函数搜索这些符号字符:*、[、]、_,它不关心任何其他字符。每次找到一个符号时,它都会处理并调用一个 Objective C 方法,传递符号的位置。

C 代码:

typedef void (* callback)(void *context, size_t location);

void process(const uint8_t *data, size_t length, callback cb, void *context)
{
    size_t i = 0;
    while (i < length)
    {
        if (data[i] == '*' || data[i] == '[' || data[i] == ']' || data[i] == '_')
        {
            int valid = 0;
            //do something, set valid = 1

            if (valid)
                cb(context, i);
        }
        i++;
    }
}

目标 C 代码:

//a C function declared in .m file
void mycallback(void *context, size_t location)
{
    [(__bridge id)context processSymbolAtLocation:location];
}

- (void)processSymbolAtLocation:(NSInteger)location
{
    NSString *result = [self.string substringWithRange:NSMakeRange(location, 1)];
    NSLog(@"%@", result);
}

- (void)processUserInput:(NSString*)string
{
    self.string = string;
    //convert string to data
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    //pass data to C function
    process(data.bytes, data.length, mycallback, (__bridge void *)(self));
}

如果输入字符串仅包含英文字符,则代码可以正常工作。如果它包含组合字符序列、多字节字符或其他 unicode 字符,则processSymbolAtLocation 方法中的结果字符串不是预期的符号。

如何正确地将 NSString 对象转换为 NSData?如何获取正确的位置?

谢谢!

【问题讨论】:

    标签: ios objective-c c macos unicode


    【解决方案1】:

    您的问题是您从 UTF-16 编码的 NSString 开始,并生成一个 UTF-8 编码字节序列。以 UTF-16 表示字符串所需的代码单元数可能不等于以 UTF-8 表示字符串所需的代码单元数,因此您的两种形式中的偏移量可能不匹配 - 正如您所发现的那样。

    您为什么首先使用 C 来扫描字符串以查找匹配项?您可能想查看NSStringrangeOfCharacterFromSet:options:range: 方法,您可以使用该方法从您的集合中查找下一个出现的字符。

    如果您需要使用 C,则将您的字符串转换为 UTF-16 单词序列,并在 C 端使用 uint16_t

    HTH

    【讨论】:

    • 如果我在 ObjC 中更改为 NSUTF16StringEncoding,在 C 中更改为 uint16_t,如何遍历数据并检查符号字符?以及如何计算正确的偏移量?谢谢!
    • 如果您使用NSUTF16StringEncoding,那么结果将以两个字节的 BOM 开头,您需要跳过它们,例如类似data.bytes+2。或者您可以使用NSUTF16LittleEndianStringEncoding 指定字节顺序并且不包含BOM。 16 位字的数量是缓冲区大小的一半(以字节为单位),例如data.length/2 之类的东西,如果有 BOM,则减去一个。除了更改类型之外,C 函数不需要更改 - 在 C 中,“字符”常量实际上是 int 类型(而 char 是一个整数类型)所以一切都像以前一样工作。
    • 所以 data.length(如果是 NSUTF16StringEncoding 则为 2)总是是 string.length 的两倍,对吧?
    • 忽略任何 BOM,是的。 NSString 中的每个字符都是一个unichar,它是一个 UTF16 代码单元。因此,当您使用 UTF16 编码将 NSString 转换为 NSData 时,最大的变化是可能添加 BOM 和每个 16 位值的字节序 - 16 位值的数量不会改变.
    • 我使用 NSUTF16LittleEndianStringEncoding 并按照您的建议进行更改,效果很好。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 2011-04-07
    • 2012-03-03
    • 1970-01-01
    相关资源
    最近更新 更多