1

我有一个不同对象的 NSArray,例如一个 NSString 和一个 NSNumber 整数。

我有一个特定的格式字符串,我想用它来打印对象内容,而不仅仅是使用

@"%@|%@" 

但是,例如

@"%-13s|%010d"

我已经实现了以下操作来执行我在 StackOverflow 和其他地方找到的 @"%@|%@" 类型打印:

@implementation NSString (NSArrayFormatExtension)

+ (id) stringWithFormatFromNSArray: (NSString *) format array: (NSArray*) args;
{
  id *argList = malloc( sizeof( id )  * [args count] );
  [ args getObjects: argList ];

  NSString* result = [ [ [ NSString alloc ] initWithFormat: format arguments: (va_list) argList ] autorelease ];

  free(argList);

  return result; 
}

@end

调用然后打印如下:

NSString *printstring = [ NSString stringWithFormatFromNSArray: nsFormatString array: nsarray_of_objects ]

这将允许 @"%@ %@" 类型的 nsFormatStrings 打印对象内容,但不允许 @"%s %d" 类型的格式打印具有更详细格式的基础 C 类型。

我有两个问题和一些关于解决方案的想法,但不想在这里重新发明轮子。

1.) 我可以通过切换从 className 派生的类型来遍历 NSArray 项 - 当然 - 但我想知道是否有标准的方法来做到这一点。

这也意味着将格式字符串解构为单独的 % 实体(或将作为数组传递并通过它进行处理 - 不是很干净,并且需要保留任何其他非格式化条目,如上面的管道分隔符)。

2.) 使用@"%@|%@" 的上述代码在 32 位 Linux 上使用 gcc / objc / objc++ 4.6.X 及更高版本,但在 64 位 Linux 上会出现段错误,我需要让它运行两个都。

根据我的阅读,这似乎是一些 Linux 系统上 va_list 的 64 位实现的一个相当普遍的问题。

即使我对对象格式感到满意,与特定的 C 类型格式相比,这仍然是错误的。有没有人可以解决这个问题?似乎它倾向于强制实施解决方案 1.) 在每种情况下都是可移植的,但那是

a.) 编码耗时 b.) 效率不高。

我真的需要能够进行详细的格式化以及从命令行程序打印的结果需要由完全不同的系统作为 CSV 文件或管道等读取。

我可能也想在字段之间使用不同的分隔符 - 例如

....|....;....,....#....^....

如果我能那样做,我会很好地嵌入我的格式字符串中。

因此,任何带有单个“连接”分隔符的格式也不是答案。

在 Perl 中做这种事情要容易得多 ;-) - 但是 - 这个特定的软件是用 Objc++ 编写的(与 C++ 库链接)。

感谢您的想法和建议。

4

1 回答 1

1

您的程序在某些平台上无法运行的原因是它使用了不可移植的行为 - 将 C 样式的ids 数组转换va_list为不保证可以工作:

(va_list) argList

这也是原语格式化%010d不起作用的原因:NSArray不能包含原语,所以 an用内部int表示。NSNumberint

一般来说,C(以及扩展,Objective C)不支持动态创建变量参数列表。这就是为什么您不能使用需要可变参数列表的格式化方法。

不幸的是,您的最佳选择需要大量编码。做一个这样的方法:

+ (id) stringWithFormatsFromNSArray: (NSArray*) formats array: (NSArray*) args {
    // verify that formats and args have the same number of entries
    NSMutableString *res = [NSMutableString string];
    for (int i = 0 ; i != args.count ; i++) {
        id arg = [args objectAtIndex:i];
        id fmt = [formats objectAtIndex:i];
        if ([arg isKindOfClass:[NSNumber class]]) {
            // Apply fmt to NSNumberFormatter
            NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
            [nf setFormat:fmt];
            [res appendString:[nf stringFromNumber:arg]];
        } else {
            [res appendFormat:fmt, arg];
        }
    }
    return [res copy];
}

此代码假定第一个参数是一个数组,而不是字符串。每个元素必须包含相应参数的格式。数字的格式将被传递给NSNumberFormatter,它允许您格式化表示数字的非原始对象。所有其他格式都将传递给appendFormat. 请注意,分隔符必须包含在相应对象的格式字符串中。您可以在除第一个对象之外的所有对象之前添加分隔符,或者在除尾随对象之外的所有对象之后添加分隔符。

于 2013-03-22T16:15:57.407 回答