在Objective-C中,如何使用stringWithCharacters打印N个空格?

10

以下尝试打印N个空格(例如,在示例中为12):

NSLog(@"hello%@world", [NSString stringWithCharacters:" " length:12]);

const unichar arrayChars[] = {' '};
NSLog(@"hello%@world", [NSString stringWithCharacters:arrayChars length:12]);

const unichar oneChar = ' ';
NSLog(@"hello%@world", [NSString stringWithCharacters:&oneChar length:12]);

但它们都会输出奇怪的东西,比如hello ÔÅÓñüÔÅ®Óñü®ÓüÅ®ÓñüÔ®ÓüÔÅ®world… 我以为“char数组”和“字符串”以及“指向字符的指针”是一样的?API规范说它应该是“Unicode字符的C数组”(通过Unicode,是UTF8吗?如果是,那么它应该与ASCII兼容)…如何使其正常工作,以及为什么这三种方法无法工作?

5个回答

17

这将帮您得到您想要的:

NSLog(@"hello%@world", [@"" stringByPaddingToLength:12 withString:@" " startingAtIndex:0]);

那,我的好先生,你正在完成什么并且没有代码格式化,这不是很清楚。-1。 - Richard J. Ross III
3
没问题,@trudyscousin。我还点了一个赞因为我觉得那个踩有些不公平。 - Alladinian

17

您可以使用%*s来指定宽度。

NSLog(@"Hello%*sWorld", 12, "");

参考资料:

字段宽度或精度,或两者都可以用星号('*')表示。 在这种情况下,类型为int的参数提供字段宽度或精度。 如果有要转换的参数,则应用程序应确保在该参数之前以指定字段宽度、精度或两者的顺序出现。


哇,这很酷。唯一的缺点是它只适用于NSLog-stringWithFormat:,它们都相当慢。但是,如果你想要一个“只需工作”的东西,这比我的答案更容易嵌入到你的应用程序中。 - Richard J. Ross III
是的,我正在尝试回忆它的名字并查找一个链接(很难在谷歌中搜索%*),我之前在某个地方回答过这个问题。在http://en.cppreference.com/w/cpp/io/c/fprintf中找到了相关内容。 - Joe
很好。如果要打印出一条分隔线,比如重复72次的“=”符号,这个方法是否也可以进行调整或类似的方式使其工作? - Jeremy L
没有*只是允许你动态设置宽度,空格用于间距。 - Joe
@Joe 啊,那就是一个相当大的缺点。真是太遗憾了。 - Richard J. Ross III
@RichardJ.RossIII 是的,但它确实回答了“如何打印N个空格?”这个问题。 - Joe

7

我认为你遇到的问题是你误解了+(NSString *)stringWithCharacters:length:的作用。它的作用不是重复字符,而是将它们从数组中复制到字符串中。

因此,在你的情况下,数组中只有一个空格,这意味着其他11个字符将从内存中跟随arrayChars之后的位置中获取。

如果你想打印出n个空格的模式,最简单的方法是使用-(NSString *)stringByPaddingToLength:withString:startingAtIndex:,即创建像这样的东西。

NSString *formatString = @"Hello%@World";
NSString *paddingString = [[NSString string] stringByPaddingToLength: n withString: @" " startingAtIndex: 0];
NSLog(formatString, paddingString);

请注意,-stringByPaddingToLength: 方法本质上是慢的。它必须分配一个比当前字符串大的缓冲区,复制当前字符串的内容,然后插入和移动字符串中的所有字符。这就是为什么我的方法性能更好,因为它依赖于极快的 C-API。 - Richard J. Ross III
3
当然,但是原帖作者可能更喜欢使用抽象的方法来提高可读性和简洁性。请记住,问题在于理解API的工作原理。 - Henri Normak

4

这可能是最快的方法:

NSString *spacesWithLength(int nSpaces)
{
    char UTF8Arr[nSpaces + 1];

    memset(UTF8Arr, ' ', nSpaces * sizeof(*UTF8Arr));
    UTF8Arr[nSpaces] = '\0';

    return [NSString stringWithUTF8String:UTF8Arr];
}

你当前的代码无法工作的原因是,+stringWithCharacters:方法需要一个长度为12的数组,而你的数组只有一个字符长度{' '}。因此,为了解决这个问题,你必须为你的数组创建一个缓冲区(在这种情况下,我们使用char数组,而不是unichar数组,因为我们可以很容易地用memset设置char数组,但不能对unichar数组这样做)。
我提供的以上方法可能是动态长度最快的解决方案。如果你愿意使用GCC扩展,并且你有一个需要的固定大小空格的数组,你可以这样做:
NSString *spacesWithLength7()
{
    unichar characters[] = { [0 ... 7] = ' ' };
    return [NSString stringWithCharacters:characters length:7];
}

很不幸,该扩展不支持变量,所以它必须是一个常量。

通过GCC扩展和预处理器宏的魔力,我为您提供了... REPEATENATOR!只需传入一个字符串(或字符),它会完成剩下的事情!现在购买,仅售19.95美元,操作员正在等待接单!(基于@JeremyL建议的想法)

// step 1: determine if char is a char or string, or NSString.
// step 2: repeat that char or string
// step 3: return that as a NSString
#define repeat(inp, cnt) __rep_func__(@encode(typeof(inp)), inp, cnt) 

// arg list: (int siz, int / char *input, int n)
static inline NSString *__rep_func__(char *typ, ...)
{
    const char *str = NULL;
    int n;

    {
        va_list args;
        va_start(args, typ);

        if (typ[0] == 'i')
            str = (const char []) { va_arg(args, int), '\0' };
        else if (typ[0] == '@')
            str = [va_arg(args, id) UTF8String];
        else
            str = va_arg(args, const char *);

        n = va_arg(args, int);

        va_end(args);
    }

    int len = strlen(str);
    char outbuf[(len * n) + 1];

    // now copy the content
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < len; j++) {
            outbuf[(i * len) + j] = str[j];
        }
    }

    outbuf[(len * n)] = '\0';
    return [NSString stringWithUTF8String:outbuf];
}

我只希望这些方法是内置的... 我认为TRS-80 Basic有类似于string(" ", 12)的东西,那样就可以工作了,如果在Ruby中," " * 12... 如果Objective-C可能有像@" ".repeat(12)这样的内置功能,那就太好了。(虽然Objective-C已经很好了) - Jeremy L
@JeremyL 我同意。虽然使用宏可以高效地编写代码,但我不知道它真正有多有用。 - Richard J. Ross III
@JeremyL 看看我刚写的宏。它允许你使用 repeat("test", 5) 或者 repeat('t', 12),并且会为 C 字符串和 char 做你想要的事情!(我还可以添加 NSString 的支持)。 - Richard J. Ross III

3
stringWithCharaters:length:方法使用C数组中前length个字符创建一个NSString(或NSString的子类实例)。它不会迭代给定的字符数组,直到达到长度。
您看到的输出是从传递的1个Unicode字符数组的位置开始的12个Unicode字符长的内存区域。
这应该能够正常工作。
NSLog(@"hello%@world", [NSString stringWithCharacters:"            " length:12]);

在这种情况下,为什么不使用NSString字面量呢?几乎难以阅读。 - Richard J. Ross III
2
原始问题是为什么这个特定的方法调用没有给出预期的结果。我的例子只是为了展示如何调用特定的方法来获得预期的结果。我的答案是为了帮助澄清这个方法的工作原理。这是一个如此简单的问题,我假设原帖作者需要了解这个方法。因此,我对他的代码进行了最小编辑,以获得他期望的结果。 - Mr. Berna

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