开发者

Elegant way to split string into 2 strings on word boundaries to minimize length difference

I have a working solution right now, but it seems really ugly for something so (seemingly) simple.

I tried just breaking it when adding a word goes over the halfway mark, both splitting before and after adding the word, but depending on the length of the words it's either imbalanced towards the first or second line.

Sample inputs that I was initi开发者_运维问答ally having trouble with before the convoluted fix:

Input "Macaroni Cheese" and "Cheese Macaroni"

Should output "Macaroni<br/> Cheese" and "Cheese<br/> Macaroni" respectively.

But simpler solutions either worked on the first but not the second, or the other way around.

So here's what I have that works, but I'm wondering if there's a more elegant way to do this.

public string Get2LineDisplayText(string original)
{
    string[] words = original.Split(new[] {' ', '\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);

    //Degenerate case with only 1 word
    if (words.Length <= 1)
    {
        return original;
    }

    StringBuilder builder = new StringBuilder();
    builder.Append(words[0]); //Add first word without prepending space
    bool addedBr = false;
    foreach (string word in words.Skip(1))
    {
        if (builder.Length + word.Length < original.Length / 2) //Word fits on the first line without passing halfway mark
        {
            builder.Append(' ' + word);
        }
        else if (!addedBr) //Adding word goes over half, need to see if it's more balanced on the 1st or 2nd line
        {
            int diffOnLine1 = Math.Abs((builder.Length + word.Length) - (original.Length - builder.Length - word.Length));
            int diffOnLine2 = Math.Abs((builder.Length) - (original.Length - builder.Length));
            if (diffOnLine1 < diffOnLine2)
            {
                builder.Append(' ' + word);
                builder.Append("<br/>");
            }
            else
            {
                builder.Append("<br/>");
                builder.Append(' ' + word);
            }
            addedBr = true;
        }
        else //Past halfway and already added linebreak, just append
        {
            builder.Append(' ' + word);
        }
    }

    return builder.ToString();
}

Sample input/output:


Here's what I came up with:

    public static string Get2Lines(string input)
    {
        //Degenerate case with only 1 word
        if (input.IndexOf(' ') == -1)
        {
            return input;
        }
        int mid = input.Length / 2;

        int first_index_after = input.Substring(mid).IndexOf(' ') + mid;
        int first_index_before = input.Substring(0, mid).LastIndexOf(' ');

        if (first_index_after - mid < mid - first_index_before)
            return input.Insert(first_index_after, "<BR />");
        else
            return input.Insert(first_index_before, "<BR />");
    }


public static string Get2LineDisplayText(string original)
{
    //Degenerate case with only 1 word
    if (!original.Any(Char.IsWhiteSpace))
    {
        return original;
    }
    int mid = original.Length / 2;
    if (!Char.IsWhiteSpace(original[mid]))
    {
        for (int i = 1; i < mid; i += i)
        {
            if (Char.IsWhiteSpace(original[mid + i]))
            {
                mid = mid + i;
                break;
            }
            if (Char.IsWhiteSpace(original[mid - i]))
            {
                mid = mid - i;
                break;
            }
        }
    }

    return original.Substring(0, mid)
           + "<br />" + original.Substring(mid + 1);
}


I tried my hand at it and arrived at :

String splitInMiddle(String s) {
    int middle = s.length() / 2;
    int right = s.indexOf(" ",middle);
    int left = s.lastIndexOf(" ",middle);

    int split = right;
    if ((right < 0) || (left + right > 2*middle)) {
        split = left;
    }
    return s.substring(0, split) + "<br/>\n" + s.substring(split + 1);
}

The principle is that it looks for the first space after and the last space before. If the left one is closer than the right one pick that.

Then glue the pieces I want with a CR instead of a space.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜