代码之家  ›  专栏  ›  技术社区  ›  Davy8

将字符串拆分为单词边界上的两个字符串以最小化长度差异的优雅方法

  •  2
  • Davy8  · 技术社区  · 14 年前

    我现在有一个可行的解决方案,但对于如此(看似)简单的事情来说,它看起来真的很难看。

    在复杂的修复之前,我最初遇到的输入示例:

    输入 "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 回复  |  直到 14 年前
        1
  •  3
  •   Davy8    14 年前

    我想到的是:

        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
  •  2
  •   Davy8    14 年前
    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);
    }
    
        3
  •  1
  •   Peter Tillemans    14 年前

    我试了试,结果:

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

    其原理是寻找后面的第一个空格和前面的最后一个空格。 如果左边的比右边的近,就选那个。

    然后用CR而不是空格来粘我想要的东西。