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

将长字符串分成60个字符长的行,但不要打断单词

  •  4
  • Tigran  · 技术社区  · 15 年前

    必须有更好的方法来做到这一点。 我只想把长字符串分成60个字符的行,但不要打断单词。所以它不需要加60个字符,只需要小于60个。

    下面的代码是我拥有的,它可以工作,但我认为有更好的方法。有人吗?

    修改为使用StringBuilder并修复了删除重复单词的问题。 也不想使用regex,因为我认为这比我现在的效率要低。

    public static List<String> FormatMe(String Message)
    {
        Int32 MAX_WIDTH = 60;
        List<String> Line = new List<String>();
        String[] Words;
    
        Message = Message.Trim();
        Words = Message.Split(" ".ToCharArray());
    
        StringBuilder s = new StringBuilder();
        foreach (String Word in Words)
        {
            s.Append(Word + " ");
            if (s.Length > MAX_WIDTH)
            {
                s.Replace(Word, "", 0, s.Length - Word.Length);
                Line.Add(s.ToString().Trim());
                s = new StringBuilder(Word + " ");
            }
        }
    
        if (s.Length > 0)
            Line.Add(s.ToString().Trim());
    
        return Line;
    }
    

    谢谢

    7 回复  |  直到 9 年前
        1
  •  0
  •   Community kfsone    7 年前

    试试这个:

    const Int32 MAX_WIDTH = 60;
    
    string text = "...";
    List<string> lines = new List<string>();
    StringBuilder line = new StringBuilder();
    foreach(Match word in Regex.Matches(text, @"\S+", RegexOptions.ECMAScript))
    {
        if (word.Value.Length + line.Length + 1 > MAX_WIDTH)
        {
            lines.Add(line.ToString());
            line.Length = 0;
        }
        line.Append(String.Format("{0} ", word.Value));
    }
    
    if (line.Length > 0)
        line.Append(word.Value);
    

    请同时查看: How do I use a regular expression to add linefeeds?

        2
  •  6
  •   Community kfsone    7 年前

    另一个(现在测试的)样品,非常类似于 Keith approach :

    static void Main(string[] args)
    {
        const Int32 MAX_WIDTH = 60;
    
        int offset = 0;
        string text = Regex.Replace(File.ReadAllText("oneline.txt"), @"\s{2,}", " ");
        List<string> lines = new List<string>();
        while (offset < text.Length)
        {
            int index = text.LastIndexOf(" ", 
                             Math.Min(text.Length, offset + MAX_WIDTH));
            string line = text.Substring(offset,
                (index - offset <= 0 ? text.Length : index) - offset );
            offset += line.Length + 1;
            lines.Add(line);
        }
    }
    

    我在上面写的 this file 将所有换行符手动替换为“”。

        3
  •  1
  •   John K    15 年前

    在正则表达式中,match evaluator函数(匿名方法)执行grunt工作,并将新大小的行存储到StringBuilder中。我们不使用regex.replace方法的返回值,因为我们只是使用它的match evaluator函数作为一个功能来完成正则表达式调用内部的换行,这只是为了检查它,因为我认为它很酷。

    using System;
    using System.Text;
    using System.Text.RegularExpressions;
    

    斯特林 是要转换的行。

    int MAX_LEN = 60;
    StringBuilder sb = new StringBuilder();
    int bmark = 0; //bookmark position
    
    Regex.Replace(strInput, @".*?\b\w+\b.*?", 
        delegate(Match m) {
            if (m.Index - bmark + m.Length + m.NextMatch().Length > MAX_LEN 
                    || m.Index == bmark && m.Length >= MAX_LEN) {
                sb.Append(strInput.Substring(bmark, m.Index - bmark + m.Length).Trim() + Environment.NewLine);
                bmark = m.Index + m.Length;
            } return null;
        }, RegexOptions.Singleline);
    
    if (bmark != strInput.Length) // last portion
        sb.Append(strInput.Substring(bmark));
    
    string strModified = sb.ToString(); // get the real string from builder
    

    同样值得注意的是,匹配评估器中if表达式中的第二个条件 m.Index == bmark && m.Length >= MAX_LEN 这是一个特殊的条件,如果有一个词超过60个字符(或超过设置的最大长度)-它不会被分解在这里,但只存储在一行本身-我想你可能想创建一个第二个公式,为该条件在现实世界中的断字或其他东西。

        4
  •  0
  •   James Black    15 年前

    我将从保存原始字符串的长度开始。然后,从后面开始,再减去,因为从最后一个单词开始,然后再回到后面,我的概率会比增加的速度快60以下。

    一旦我知道有多长时间,那么只需使用StringBuilder并为新字符串构建字符串。

        5
  •  0
  •   Keith Randall    15 年前
    List<string> lines = new List<string>();
    while (message.Length > 60) {
      int idx = message.LastIndexOf(' ', 60);
      lines.Add(message.Substring(0, idx));
      message = message.Substring(idx + 1, message.Length - (idx + 1));
    }
    lines.Add(message);
    

    您可能需要修改一点以处理多个空格,其中包含60个字符的单词,…

        6
  •  0
  •   Dmitrii Lobanov    13 年前

    另一个…

    public static string SplitLongWords(string text, int maxWordLength)
    {
        var reg = new Regex(@"\S{" + (maxWordLength + 1) + ",}");
        bool replaced;
        do
        {
            replaced = false;
            text = reg.Replace(text, (m) =>
            {
                replaced = true;
                return m.Value.Insert(maxWordLength, " ");                    
            });
        } while (replaced);
    
        return text;
    }
    
        7
  •  0
  •   Jim Borland    9 年前

    我试过原始的解决方案,发现它不太管用。我稍微修改了一下,使它能工作。它现在对我有效,解决了我遇到的一个问题。谢谢。 吉姆。

    public static List<String> FormatMe(String message)
        {
            int maxLength = 10;
            List<String> Line = new List<String>();
            String[] words;
    
            message = message.Trim();
            words = message.Split(" ".ToCharArray());
    
            StringBuilder sentence = new StringBuilder();
            foreach (String word in words)
            {
                if((sentence.Length + word.Length) <= maxLength)
                {
                    sentence.Append(word + " ");
    
                }
                else
                {
                    Line.Add(sentence.ToString().Trim());
                    sentence = new StringBuilder(word + " ");
                }
            }
    
            if (sentence.Length > 0)
                Line.Add(sentence.ToString().Trim());
    
            return Line;
        }
    
        private void btnSplitText_Click(object sender, EventArgs e)
        {
            List<String> Line = new List<string>();
            string message = "The quick brown fox jumps over the lazy dog.";
            Line = FormatMe(message);
        }