Xcode UTF-8 文本字面量

21

假设我有一个符号MUSICAL SYMBOL G CLEF:** **,我希望在我的Objective-C源文件中用字符串字面量表示它。

OS X字符查看器说CLEF是UTF8 F0 9D 84 9E和Unicode1D11E(D834+DD1E)

经过一些尝试和使用ICU UNICODE演示页面,我确实让以下代码能够工作:

NSString *uni=@"\U0001d11e";
NSString *uni2=[[NSString alloc] initWithUTF8String:"\xF0\x9D\x84\x9E"];
NSString *uni3=@"";
NSLog(@"unicode: %@ and %@ and %@",uni, uni2, uni3);

我的问题:

  1. 我是否可以优化我当前使用UTF-8字面量的方式?它似乎有点笨拙。
  2. @"\U0001d11e部分是UTF-32吗?
  3. 为什么从Character Viewer中剪切并粘贴CLEF实际上起作用了?我以为Objective-C文件必须是UTF-8格式的?

1
你的第一个解决方案让我开心了一整天。谢谢你的提问!:D - Thibault D.
这个问题已经有4千多次的访问量,但只有7个赞!我相信你不是唯一一个受益的人 :) - Thibault D.
NSLog可以正常工作,但UILabel却不行。我得到了一个“NA”。 - jdl
4个回答

11
  1. 我更喜欢你在uni3中的做法,但遗憾的是那是不推荐的。如果不行,我宁愿选择uni中的方法而不是uni2。另一个选项是[NSString stringWithFormat:@"%C", 0x1d11e]
  2. 这是一种“通用字符名称”,在C99(第6.4.3节)中引入,并在OS X 10.5中作为Objective-C的一部分导入。从技术上讲,这并不一定会给你UTF-8(由编译器决定),但实际上你可能会得到UTF-8。
  3. 源代码文件的编码可能是UTF-8,与运行时所期望的相匹配,因此一切都能正常工作。也有可能源文件是UTF-16或UTF-32,编译器在编译时会做正确的事情。尽管如此,苹果公司不建议这样做。

1
%C 只支持 16 位 Unicode 字符,因此无法处理 0x1d11e。 - an0

8

以下是按照相同顺序回答您的问题:

  1. 为什么要选择?Xcode在默认设置中使用C99。请参阅C0X草案规范6.4.3中的通用字符名称。详情见下方。

  2. 更具体地说,@"\U0001d11e是ISO 10646字符集中该字符的32位Unicode代码点。

  3. 我不会指望这种行为能够正常工作。您应该绝对、肯定、毫无疑问地让源文件中的所有字符都是7位ASCII码。对于字符串字面值,请使用编码或最好使用适合处理二进制数据的外部资源。

通用字符名称(来自WG14/N1256 C0X草案,CLANG遵循得相当好):

“通用字符名”可以用于标识符、字符常量和字符串字面值中,以指定不属于基本字符集的字符。其中,“\Unnnnnnnn”代表八位短标识符(由ISO/IEC 10646规定)为“nnnnnnnn”的字符;同样,“\unnnn”代表四位短标识符为“nnnn”的字符(其八位短标识符为“0000nnnn”)。因此,您可以以一种自然、混合的方式生成字符或字符串。
char *utf8CStr = 
   "May all your CLEF's \xF0\x9D\x84\x9E be left like this: \U0001d11e";
NSString *uni4=[[NSString alloc] initWithUTF8String:utf8CStr];
\Unnnnnnnn形式允许您选择任何Unicode代码点,这与字符查看器左下角的“Unicode”字段的值相同。在C99源文件中直接输入\Unnnnnnnn将由编译器适当处理。请注意,只有两个选项:\unnnn是默认代码页的256个字符偏移量,\Unnnnnnnn是任何Unicode代码点的完整32位字符。如果您没有使用所有4个或所有8个数字或\u或\U,则需要在左侧填充0。
在同一字符串文字中\xF0\x9D\x84\x9E的形式更加有趣。这是插入相同字符的原始UTF-8编码。一旦传递给initWithUTF8String方法,但字面量和编码字面量最终都被编码为UTF-8。

也许,使用原始字节可能是第5.1.1.2节的130条的违规行为。考虑到原始UTF-8字符串将类似地编码,我认为你没问题。


1
在这种情况下,使用原始字节肯定不违反5.1.1.2节的130条款。 "token concatenation" 是指使用预处理器中的##运算符将标记粘合在一起,例如将\u1234粘合在一起以获得\u1234,这与字符串文字中使用的字节表示UTF-8字符无关。 - Anomie
我说过,“我”认为这很好,而且听起来你也这么认为。我确实遇到过一个非常热情的人,他变得红脸青筋地说,在单个字符串中使用多个编码不好,实际上是一种安全风险。我主要是因为他曾经被解雇的记忆而传递这个警告... - dawg
字符串中的多个编码无疑会搞乱自动检测编码的探测器。但是,你的情况可能有所不同。 - dawg
风格不好,可能存在安全风险。但这与5.1.1.2节的第130条完全无关。 - Anomie

2
  1. You can write the clef character in your string literal, too:

    NSString *uni2=[[NSString alloc] initWithUTF8String:""];
    
  2. The \U0001d11e matches the unicode code point for the G clef character. The UTF-32 form of a character is the same as its codepoint, so you can think of it as UTF-32 if you want to. Here's a link to the unicode tables for musical symbols.

  3. Your file probably is UTF-8. The G clef is a valid UTF8 character - check out the output from hexdump for your file:

    00  4e 53 53 74 72 69 6e 67  20 2a 75 6e 69 33 3d 40  |NSString *uni3=@|
    10  22 f0 9d 84 9e 22 3b 0a  20 20 4e 53 4c 6f 67 28  |"....";.  NSLog(|
    

    As you can see, the correct UTF-8 representation of that character is in the file right where you'd expect it. It's probably safer to use one of your other methods and try to keep the source file in the ASCII range.


0

我创建了一些实用类,可以轻松地在Unicode代码点、UTF-8字节序列和NSString之间进行转换。你可以在Github上找到代码,也许对某些人有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接