В Objective-C, как распечатать N пробелов? (используя stringWithCharacters)

При попытке распечатать 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 говорит, что это должен быть "массив C символов Unicode" (по Unicode, это UTF8? Если он есть, то он должен быть совместим с ASCII)... Как заставить его работать и почему эти 3 пути выиграли Не работает?

Ответ 1

Вы можете использовать %*s для указания ширины.

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

Ссылка:

Ширина поля, или точность, или и то, и другое могут быть обозначены звездочкой ('*'). В этом случае аргумент типа int предоставляет ширину поля или точности. Приложения должны гарантировать, что аргументы, указывающие ширину поля или точность, или оба появляются в этом порядке до аргумент, если таковой имеется, для преобразования.

Ответ 2

Это даст вам то, что вы хотите:

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

Ответ 3

Я думаю, что проблема заключается в том, что вы неверно истолковываете то, что должен делать +(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);

Ответ 4

Это, вероятно, самый быстрый способ:

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

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

    return [NSString stringWithUTF8String:UTF8Arr];
}

Причина, по которой ваш текущий код не работает, состоит в том, что +stringWithCharacters: ожидает массив с длиной символов 12, а ваш массив имеет длину всего 1 символ {' '}. Итак, чтобы исправить, вы должны создать буфер для своего массива (в этом случае мы используем массив char, а не unichar), потому что мы можем легко memset a char массив, но не unichar).

Метод, описанный выше, вероятно, является самым быстрым, что возможно с динамической длиной. Если вы хотите использовать расширения GCC и у вас есть массив требуемых размеров, вы можете сделать это:

NSString *spacesWithLength7()
{
    unichar characters[] = { [0 ... 7] = ' ' };
    return [NSString stringWithCharacters:characters length:7];
}

К сожалению, это расширение не работает с переменными, поэтому оно должно быть константой.

Через магию расширений GCC и макросов препроцессора я даю вам... ПОВТОРНИК! Просто передайте строку (или char), и она сделает все остальное! Купить сейчас, стоит вам всего $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];
}

Ответ 5

Метод stringWithCharaters:length: делает NSString (или экземпляр подкласса NSString) с использованием символов первой длины в массиве C. Он не перебирает заданный массив символов, пока не достигнет длины.

Вы видите, что вы видите область памяти. 12 символов Юникода, длинные, начиная с местоположения вашего переданного массива символов Юникода.

Это должно работать.

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