2

我被问了一个问题,现在我因为无法得出准确/正确的结果而自责。

想象一下,我们有一个函数可以将一个字符串拆分为多行,但在我们“拆分”到新行之前,每行必须有 x 个字符:

private string[] GetPagedMessages(string input, int maxCharsPerLine) { ... }

对于每一行,我们需要在行尾加入“x/y”,基本上是 1/4、2/4 等……现在,分页机制也必须是每行长度限制的一部分。

我已经过度劳累,过度思考和绊倒,这似乎很简单,但对于我的生活,我无法弄清楚!我没有“得到”什么?

我对什么感兴趣?计算和部分逻辑,但主要是根据每行的最大字符数计算需要多少行来拆分输入,这也需要包括 x/y。

请记住:x/y 可以有多个数字(即:不仅是 1/4,还有 10/17 或 99/200)

样品:

input = "这是一条长消息"

maxCharsPerLine = 10

输出:

This i 1/4 // << Max 10 chars
s a lo 2/4 // << Max 10 chars
ng mes 3/4 // << Max 10 chars
sage 4/4 // << Max 10 chars

总的来说,逻辑很简单,但它只是让我失望的计算。

4

2 回答 2

2

思路:首先,求行数是多少位数:

(n = input.Length, maxCharsPerLine = 10)
if n <= 9*(10-4)  ==> 1 digit
if n <= 9*(10-5) + 90*(10-6)  ==> 2 digits
if n <= 9*(10-6) + 90*(10-7) + 900*(10-8)  ==> 3 digits
if n <= 9*(10-7) + 90*(10-8) + 900*(10-9) + 9000*(10-10)  ==> No solution

然后,减去多余的行数。解决方案:

    private static int GetNumberOfLines(string input, int maxCharsPerLine)
    {
        int n = input.Length;
        int x = maxCharsPerLine;

        for (int i = 4; i < x; i++)
        {
            int j, sum = 0, d = 9, numberOfLines = 0;

            for (j = i; j <= i + i - 4; j++)
            {
                if (x - j <= 0)
                    return -1;   // No solution

                sum += d * (x - j);
                numberOfLines += d;
                d *= 10;
            }
            if (n <= sum)
                return numberOfLines - (sum - n) / (x - j + 1);
        }
        return -2;   // Invalid
    }

用法:

    private static string[] GetPagedMessages(string input, int maxCharsPerLine)
    {
        int numberOfLines = GetNumberOfLines(input, maxCharsPerLine);
        if (numberOfLines < 0)
            return null;

        string[] result = new string[numberOfLines];

        int spaceLeftForLine = maxCharsPerLine - numberOfLines.ToString().Length - 2;  // Remove the chars of " x/y" except the incremental 'x'
        int inputPosition = 0;
        for (int line = 1; line < numberOfLines; line++)
        {
            int charsInLine = spaceLeftForLine - line.ToString().Length;
            result[line - 1] = input.Substring(inputPosition, charsInLine) + $" {line}/{numberOfLines}";
            inputPosition += charsInLine;
        }
        result[numberOfLines-1] = input.Substring(inputPosition) + $" {numberOfLines}/{numberOfLines}";
        return result;
    }
于 2021-01-28T18:18:37.727 回答
1

一种天真的方法是开始计算行长度减去“寻呼机”的大小,直到行数的大小发生变化(“1/9”比“1/10”短,比“11/20”短, 等等):

private static int[] GetLineLengths(string input, int maxCharsPerLine)
{
    /* The "pager" (x/y) is at least 4 characters (including the preceding space) and at most ... 8?
    * 7/9     (4)
    * 1/10    (5)
    * 42/69   (6)
    * 3/123   (6)
    * 42/420  (7)
    * 999/999 (8)
    */

    int charsRemaining = input.Length;

    var lineLengths = new List<int>();

    // Start with " 1/2", (1 + 1 + 2) = 4 length
    var highestLineNumberLength = 1;

    var lineNumber = 0;
    do
    {
        lineNumber++;

        var currentLineNumberLength = lineNumber.ToString().Length; // 1 = 1, 99 = 2, ...
        if (currentLineNumberLength > highestLineNumberLength)
        {
            // Pager size changed, reset
            highestLineNumberLength = currentLineNumberLength;
            lineLengths.Clear();
            lineNumber = 0;
            charsRemaining = input.Length;
            continue;
        }

        var pagerSize = currentLineNumberLength + highestLineNumberLength + 2;
        var lineLength = maxCharsPerLine - pagerSize;

        if (lineLength <= 0)
        {
            throw new ArgumentException($"Can't split input of size {input.Length} into chunks of size {maxCharsPerLine}");
        }

        lineLengths.Add(lineLength);

        charsRemaining -= lineLength;

    }
    while (charsRemaining > 0);

    return lineLengths.ToArray();
}

用法:

private static string[] GetPagedMessages(string input, int maxCharsPerLine)
{
    if (input.Length <= maxCharsPerLine)
    {
        // Assumption: no pager required for a message that takes one line
        return new[] { input };
    }

    var lineLengths = GetLineLengths(input, maxCharsPerLine);

    var result = new string[lineLengths.Length];

    // Cut the input and append the pager
    var previousIndex = 0;
    for (var i = 0; i < lineLengths.Length; i++)
    {
        var lineLength = Math.Min(lineLengths[i], input.Length - previousIndex); // To cater for final line being shorter
        result[i] = input.Substring(previousIndex, lineLength) + " " + (i + 1) + "/" + lineLengths.Length;
        previousIndex += lineLength;
    }

    return result;
}

打印,例如:

This  1/20
is a  2/20
long  3/20
strin 4/20
g tha 5/20
t wil 6/20
l spa 7/20
n mor 8/20
e tha 9/20
n te 10/20
n li 11/20
nes  12/20
beca 13/20
use  14/20
of i 15/20
ts e 16/20
norm 17/20
ous  18/20
leng 19/20
th 20/20
于 2021-01-28T11:10:52.480 回答