Верните обернутую словом NSString из более длинного NSString

Возможный дубликат:
UITextView: получите текст с информацией об обертке

Я исследовал библиотеку NSString и многочисленные библиотеки для функции, которая может принимать длинную строку следующим образом:

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui.

и вместе с CGSize или float, указывающими ширину и используемый шрифт, и возвращаем мне строку с \n перерывами и словами, завернутыми.

Результат (примерно):

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac\n
egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet.\n
 Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. \n
placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra.\n
 Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi.\n
 Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci,\n
 sagittis tempus lacus enim ac dui. 

Я уже знаю, что UITextViews и т.д. делают это, но это не помогает, поскольку мне нужно визуализировать текст в необработанном ландшафте OpenGL, поэтому я не использую обычные элементы пользовательского интерфейса.

Я знаю, что это либо существует как фреймворк, либо публичный класс. Я просто не могу найти какой-либо унифицированный способ обработки этого.

Я предполагаю, что он близок к [NSString sizeWithFont: forWidth: lineBreakMode:], но мне не нужен размер, мне нужна сама строка.

Ответ 1

На самом деле нет необходимости изобретать это колесо, так как это именно то, что текстовый движок делает для вас каждый раз, когда вы обертываете текст. И что такое текстовый движок? Это основной текст. Если вы опуститесь до уровня Core Text и разместите CTFramesetter текст для вас, вы можете узнать, где он помещает разрывы строк, запросив итоговые CTLines.

В документации вам будет предложено:

http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/CoreText_Programming/Operations/Operations.html

И в Интернете есть много хороших учебных пособий.

Простой пример:

NSString* s = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
@"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
@"enim ad minim veniam, quis nostrud exercitation ullamco laboris "
@"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
@"in reprehenderit in voluptate velit esse cillum dolore eu fugiat "
@"nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
@"sunt in culpa qui officia deserunt mollit.";
NSAttributedString* text = [[NSAttributedString alloc] initWithString:s];

CTFramesetterRef fs =
CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)text);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0,0,200,100000));
CTFrameRef f = CTFramesetterCreateFrame(fs, CFRangeMake(0, 0), path, NULL);
CTFrameDraw(f, NULL);

NSArray* lines = (__bridge NSArray*)CTFrameGetLines(f);
for (id aLine in lines) {
    CTLineRef theLine = (__bridge CTLineRef)aLine;
    CFRange range = CTLineGetStringRange(theLine);
    NSLog(@"%ld %ld", range.location, range.length);
}
CGPathRelease(path);
CFRelease(f);
CFRelease(fs);

Как вы увидите, на выходе отображается диапазон каждой строки обернутого текста. Разве это не то, что вам нужно?

Ответ 2

Кажется, что нет способа factory сделать это, поэтому приступили к построению функции класса для обработки этого, основываясь на решении, представленном в этом тесно связанном стеке:

+ (NSString*)wrappedString:(NSString*)string withFont:(UIFont*)font andWidth:(float)width {
    NSMutableString *resultString = [[NSMutableString alloc] initWithString:@""];

    CGSize textSize = [string sizeWithFont:font];
    float textWidth = textSize.width;
    if (textWidth < width) {
        return string;
    }
    float wordLength;
    float lineLength;
    NSUInteger length = [string length];
    unichar buffer[length];
    [string getCharacters:buffer range:NSMakeRange(0, length)];

    NSString *singleLine = @"";
    NSString *word = @"";
    NSString *longWord = @"";

    for (NSUInteger i = 0; i < length; i++) {

        unichar character = buffer[i];
        if (character != '\n') {
            word = [NSString stringWithFormat:@"%@%c", word, character];
        }

        if (character == '\n') {
            float wordLength = [word sizeWithFont:font].width;
            float lineLength = [singleLine sizeWithFont:font].width;
            if ((lineLength + wordLength) > width) {
                [resultString appendString:singleLine];
                [resultString appendString:@"\n"];
                singleLine = @"";
                singleLine = [singleLine stringByAppendingFormat:@"%@\n",word];
                word = @"";
            } else {
                singleLine = [singleLine stringByAppendingString: word];
                word = @"";
                [resultString appendString:singleLine];
                [resultString appendString:@"\n"];
                singleLine = @"";
            }
        }

        else if (character == ' ') {
            float wordLength = [word sizeWithFont:font].width;
            float lineLength = [singleLine sizeWithFont:font].width;

            if ((lineLength + wordLength) > width) {
                if (wordLength > textWidth) {
                    [resultString appendString:singleLine];
                    [resultString appendString:@"\n"];
                    singleLine = @"";
                    int j = 0;
                    for (; j < [word length]; j++) {
                        unichar longChar = [word characterAtIndex:j];
                        longWord = [NSString stringWithFormat:@"%@%c", longWord, longChar];
                        float longwordLength = [longWord sizeWithFont:font].width;
                        float longlineLength = [singleLine sizeWithFont:font].width;
                        if ((longlineLength + longwordLength) >= width) {
                            singleLine = [singleLine stringByAppendingString:longWord];
                            word = @"";
                            longWord = @"";
                            break;
                        }
                    }

                }
                [resultString appendString:singleLine];
                [resultString appendString:@"\n"];
                singleLine = @"";
            }
            singleLine = [singleLine stringByAppendingString: word];
            word = @"";
        }
    }

    wordLength = [word sizeWithFont:font].width;
    lineLength = [singleLine sizeWithFont:font].width;

    if (wordLength > 0) {
        if ((lineLength + wordLength) > width) {
            [resultString appendString:singleLine];
            [resultString appendString:@"\n"];
            singleLine = @"";
        }
        singleLine = [singleLine stringByAppendingString:word];
    }


    if (lineLength > 0) {
        [resultString appendString:singleLine];
        [resultString appendString:@"\n"];
    }
    return resultString;
}