Word wrap to X lines instead of maximum width (Least raggedness)

后端 未结 8 1776

Does anyone know a good algorithm to word wrap an input string to a specified number of lines rather than a set width. Basically to achieve the minimum width for X lines.

8条回答
  •  旧时难觅i
    2020-12-09 13:45

    This solution improves on Mikola's.

    It's better because

    1. It doesn't use strings. You don't need to use strings and concatenate them. You just need an array of their lengths. So, because of this it's faster, also you can use this method with any kind of "element" - you just need the widths.
    2. There was some unnecessary processing in the wrap_min_width function. It just kept going even when it went beyond the point of failure. Also, it just builds the string unnecessarily.
    3. Added the "separator width" as an adjustable parameter.
    4. It calculates the min width - which is really what you want.
    5. Fixed some bugs.

    This is written in Javascript:

     // For testing calcMinWidth
    
    var formatString = function (str, nLines) {
    
        var words = str.split(" ");
        var elWidths = words.map(function (s, i) {
            return s.length;
        });
    
        var width = calcMinWidth(elWidths, 1, nLines, 0.1);
    
        var format = function (width)
        {
            var lines = [];
            var curLine = null;
            var curLineLength = 0;
    
            for (var i = 0; i < words.length; ++i) {
                var word = words[i];
                var elWidth = elWidths[i];
    
                if (curLineLength + elWidth > width)
                {
                    lines.push(curLine.join(" "));
                    curLine = [word];
                    curLineLength = elWidth;
                    continue;
                }
    
                if (i === 0)
                    curLine = [word];
                else
                {
                    curLineLength += 1;
                    curLine.push(word);
                }
    
                curLineLength += elWidth;
            }
    
            if (curLine !== null)
                lines.push(curLine.join(" "));
    
            return lines.join("\n");
        };
    
        return format(width);
    };
    
    var calcMinWidth = function (elWidths, separatorWidth, lines, tolerance)
    {
        var testFit = function (width)
        {
            var nCurLine = 1;
            var curLineLength = 0;
    
            for (var i = 0; i < elWidths.length; ++i) {
                var elWidth = elWidths[i];
    
                if (curLineLength + elWidth > width)
                {
                    if (elWidth > width)
                        return false;
    
                    if (++nCurLine > lines)
                        return false;
    
                    curLineLength = elWidth;
                    continue;
                }
    
                if (i > 0)
                    curLineLength += separatorWidth;
    
                curLineLength += elWidth;
            }
    
            return true;
        };
    
    
        var hi = 0;
        var lo = null;
    
        for (var i = 0; i < elWidths.length; ++i) {
            var elWidth = elWidths[i];
    
            if (i > 0)
                hi += separatorWidth;
    
            hi += elWidth;
    
            if (lo === null || elWidth > lo)
                lo = elWidth;
        }
    
        if (lo === null)
            lo = 0;
    
        while (hi - lo > tolerance)
        {
            var guess = (hi + lo) / 2;
    
            if (testFit(guess))
                hi = guess;
            else
                lo = guess;
        }
    
        return hi;
    };
    

提交回复
热议问题