4

我正在为 Mac OS X(10.5+)编写一个 CLI 工具,它必须处理很可能包含非 ASCII 字符的命令行参数。

为了进一步处理,我使用 +[NSString stringWithCString:encoding:] 转换这些参数。

我的问题是,我找不到关于如何确定运行所述 cli-tool 的 shell 使用的字符编码的好信息。
我想出的解决方案如下:

NSDictionary *environment = [[NSProcessInfo processInfo] environment];
NSString *ianaName = [[environment objectForKey:@"LANG"] pathExtension];
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(
  CFStringConvertIANACharSetNameToEncoding( (CFStringRef)ianaName ) );

NSString *someArgument = [NSString stringWithCString:argv[someIndex] encoding:encoding];

然而,我觉得这有点粗鲁——这让我觉得我错过了一些明显的东西……但是什么?

是否有一种更理智/更清洁的方式来实现基本相同?

提前致谢

D

4

3 回答 3

1

答案取决于非 asciiness 的来源。

  1. 在 OS X 中,环境变量LANG反映GUI 中语言的选择。很少有人会LANG在命令行设置。
  2. GUI 中“系统编码”的选择存储在 中~/.CFUserTextEncoding,可以通过以下方式获得CFStringGetSystemEncoding,请参阅此Apple 文档
  3. 也就是说,这种“系统编码”很少使用,除非在非常古老的、不支持 unicode 的软件中使用。任何理智的 Cocoa 程序都只使用 Unicode,没有别的。
  4. 特别是,Cocoa 级别的文件路径总是以 UTF-8(的变体)编码。因此,NSString要从 C 字符串中获取一个,请使用

     NSString*string=[NSString stirngWithCString:cString encoding:NSUTF8Encoding];
    

    并从 中获取文件路径的 C 字符串NSString,请使用

     char*path=[string fileSystemRepresentation];
    

    此处建议不要使用 just [string UTF8String],由于其微妙之处,请参阅此Apple 文档

  5. 所以,我建议你不要关心编码,只假设 UTF-8。

  6. 也就是说,可能有极少数人LANG在命令行上设置,您可能想照顾他们。那么,你所做的就是我唯一能想到的。
于 2010-06-19T03:34:56.847 回答
1

你不能用[[NSProcessInfo processInfo] arguments]吗?

于 2015-07-02T05:09:43.833 回答
0

好吧,事实证明似乎没有!

正如 Yuji 所指出的,无论如何,文件名的底层编码都是 UTF-8。因此,需要处理两种情况

  1. 由用户逐字符输入的参数。
  2. 制表符完成的参数或类似命令的输出ls,因为它们不转换任何字符。

UTF-8 的假设简单地涵盖了第二种情况。

然而,第一种情况是有问题的:

  • 在 Mac OS 10.6 上,$LANG 包含所用编码的 IANA 名称,例如de_DE.IANA_NAME.
  • 在 Snow Leopard 之前,UTF-8 以外的字符集不是这种情况!

我没有测试我能想到的每一个字符集,但没有一个欧洲字符集包括在内。相反, $LANG 只是语言区域设置(de_DE在我的情况下)!

由于+[NSString stringWithCString:encoding:]使用不正确编码调用的结果是 undefined,因此您不能安全地假设它会nil在这种情况下返回*(例如,如果它只是 ASCII,它可能工作得非常好!)。

增加整体混乱的是,无论如何$LANG 都不能保证存在:Terminal.app 的首选项中有一个复选框,使用户根本无法设置$LANG(更不用说似乎无法处理的 X11.app任何非 ASCII 输入...)。

那么还剩下什么:

  1. 检查是否存在$LANG. 如果没有设置,Goto:4!
  2. 检查是否$LANG包含有关编码的信息。如果没有,转到:4!
  3. 检查您找到的编码是否为 UTF-8。如果是 Goto:6,否则...
  4. 如果argc大于 2 并且[[NSString stringWithCString: argv[0] encoding: NSUTF8StringEncoding] isEqualToString: yourForceUTFArgumentFlag],则打印您现在强制使用 UTF-8 并转到 6。如果不是:
  5. 假设您什么都不知道,发出警告,提示您的用户应将终端编码设置为 UTF-8,并可能考虑将yourForceUTFArgumentFlag其作为第一个参数和exit()传递。
  6. 假设 UTF-8 并做你必须做的事情......

听起来很烂?那是因为它是,但我想不出任何更明智的方法。


还有一点需要注意的是:如果您使用 UTF-8 作为编码,则 stringWithCString:encoding: 在遇到未以 UTF-8 编码的 C-String 中的非 ASCII 字符时返回 nil

于 2010-07-05T18:39:00.453 回答