Элегантный способ разбить строку на 2 строки на границах слов, чтобы минимизировать разницу в длине - PullRequest
2 голосов
/ 10 сентября 2010

У меня есть рабочее решение прямо сейчас, но оно кажется действительно уродливым для чего-то настолько (казалось бы) простого.

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

Примеры входных данных, с которыми у меня изначально были проблемы перед запутанным исправлением:

Входные данные "Macaroni Cheese" и "Cheese Macaroni"

Должны выводить "Macaroni<br/> Cheese" и "Cheese<br/> Macaroni" соответственно.

Но более простые решения работали либо с первым, но не со вторым, или наоборот.

Итак, вот что у меня работает, но мне интересно, есть ли более элегантныйспособ сделать это.

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();
}

Пример ввода / вывода:

Ответы [ 3 ]

3 голосов
/ 10 сентября 2010

Вот что я придумал:

    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 />");
    }
2 голосов
/ 10 сентября 2010
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);
}
1 голос
/ 10 сентября 2010

Я попробовал свои силы в этом и достиг:

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);
}

Принцип состоит в том, что он ищет первый пробел после и последний пробел раньше.Если левый находится ближе, чем правый, выберите это.

Затем склейте нужные мне кусочки с КР вместо пробела.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...