Objective c 在Mac OS X中获取CLI字符编码的合理(r)方法?

Objective c 在Mac OS X中获取CLI字符编码的合理(r)方法?,objective-c,command-line,foundation,Objective C,Command Line,Foundation,我正在为MacOSX(10.5+)编写一个CLI工具,它必须处理命令行参数,这些参数很可能包含非ASCII字符 为了进一步处理,我使用+[NSString stringWithCString:encoding:]转换这些参数 我的问题是,我找不到关于如何确定运行所述cli工具的shell使用的字符编码的好信息。 我提出的解决方案如下: NSDictionary *environment = [[NSProcessInfo processInfo] environment]; NSString *

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

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

我的问题是,我找不到关于如何确定运行所述cli工具的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];
然而,我发现这有点粗糙——这让我觉得我遗漏了一些明显的东西……但是什么呢

是否有一种更明智/更清洁的方法来实现基本相同的目标

提前谢谢


答案取决于非粘性的来源

  • 在OSX中,环境变量
    LANG
    并不反映GUI中的语言选择。很少有人会在命令行中设置
    LANG
  • GUI上的“系统编码”选项存储在
    ~/.cfusertextcodencing
    中,可以通过
    CFStringGetSystemEncoding
    获得,请参见此
  • 也就是说,这种“系统编码”很少使用,除非是在非常旧的、不支持unicode的软件中。任何理智的Cocoa程序都只使用Unicode而不使用其他任何东西
  • 特别是,Cocoa级别的文件路径始终以UTF-8(一种变体)编码。因此,要从C字符串中获取
    NSString
    ,请使用

     NSString*string=[NSString stirngWithCString:cString encoding:NSUTF8Encoding];
    
    要从
    NSString
    获取文件路径的C字符串,请使用

     char*path=[string fileSystemRepresentation];
    
    这里建议不要只使用
    [string UTF8String]
    ,由于其微妙之处,请参见此

  • 因此,我建议您不要关心编码,只假设UTF-8

  • 也就是说,可能有极少数人在命令行上设置
    LANG
    ,而您可能需要照顾他们。那么,你所做的是我唯一能想到的

  • 好吧,结果似乎没有

    正如Yuji所指出的,文件名的底层编码是UTF-8,不管怎样。因此,需要处理两种情况:

  • 由用户逐个字符输入的参数
  • 制表符完成的参数或命令(如
    ls
    )的输出,因为它们不转换任何字符
  • UTF-8假设仅涵盖了第二种情况

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

    • 在Mac OS 10.6上,$LANG包含所用编码的IANA名称,如
      de_de.IANA_name
    • 在使用SnowLeopard之前,字符集的情况并非如此,UTF-8除外
    我没有测试我能想到的每一个字符集,但没有一个欧洲字符集被包括在内。相反,$LANG只是语言环境(
    de_de
    在我的例子中)

    由于使用不正确的编码调用
    +[NSString stringWithCString:encoding://code>的结果,,因此您不能安全地假设在这种情况下它将返回
    nil
    *(例如,如果它仅为ASCII,则可能工作得很好!)

    更糟糕的是,
    $LANG
    并没有得到保证,不管怎样:在Terminal.app的首选项中有一个复选框,允许用户根本不设置
    $LANG
    (更不用说X11.app了,它似乎不处理任何非ASCII输入…)

    剩下的是:

  • 检查是否存在
    $LANG
    。如果没有设置,转到:4
  • 检查
    $LANG
    是否包含编码信息。如果没有,转到:4
  • 检查您找到的编码是否为UTF-8。如果是转到:6,否则
  • 如果
    argc
    大于2且
    [[NSString stringWithCString:argv[0]编码:NSUTF8StringEncoding]IseQualtString:yourForceUTFArgumentFlag]
    ,则打印您正在强制UTF-8并转到6。如果没有:
  • 假定您不知道任何东西,发出警告,您的用户应该将终端编码设置为UTF-8,并可以考虑传递<代码> UyFuffutfAgMutug标记< /C>作为第一个参数和<强> Ext()<<强> > /LI>。
  • 假设UTF-8,做你必须做的
  • 听起来很糟糕?那是因为它是,但我想不出任何更明智的方法


    但还有一点需要注意:
    如果您使用UTF-8作为编码,stringWithCString:encoding:每当遇到未在UTF-8中编码的C字符串中的非ASCII字符时,返回nil。)

    您不能使用
    [[NSProcessInfo processInfo]参数]

    来澄清一下:我编写的工具不是GUI程序,但是一个命令行工具链接到
    Foundation.h
    ;正在进行的字符串转换是从C-string到
    NSString
    。因此,编码取决于命令行环境的设置。它可以很容易地通过Terminal.app的首选项进行更改。我没有直接发表评论,因为我希望得到更多答案;-)好的,非ASCINESS是固有的,因为我的用户是德国人,命令行参数是文件名。更重要的是,这些文件可能会有人的名字,所以我必须处理“魏穆勒”、“厄尔曼”之类的问题。因为这不是一个GUI应用程序,而是一个命令行工具,所以CFStringGetSystemEncoding无法剪切它,因为它与Terminal.app使用的内容无关(就个人而言,我大部分时间在Terminal中使用UTF-8,但~/.CFUserTextEncoding表示默认的“MacRoman”)。还有一件事。。。虽然这与我目前正在做的事情没有多大关系,但谢谢你提到TN1150,因为我不知道!???OSX上的文件名本质上是BSD级别的UTF-8,与终端首选的编码选择无关。(或者至少日本人是这样的