2009-11-05 81 views
4

必须有更好的方法才能做到这一点。 我只是想将长字符串分成60个字符行,但不要打破单词。所以它不需要加起来60个字符只需少于60.将长长的字符串分成60个字符长的字符串,但不要打破单词

下面的代码是我有,它的工作原理,但我认为有一个更好的方法。任何人?

修改为使用StringBuilder并修复了删除重复单词的问题。 也不想使用正则表达式,因为我认为这会比现在低效。

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

感谢

+0

您是在寻找一种更高效的算法或更多的下一个编码器来阅读这种友好的方法吗? – Nate 2009-11-05 03:04:46

+0

你没有使用泛型的原因? – Nate 2009-11-05 03:07:44

+1

1.您的代码无法按预期工作。 s.Replace(Word,“”)不仅会替换最后一个,而且还会替换字符串中Word的任何部分匹配。 2. s + = ...您将最终创建太多临时字符串对象,因为字符串在C#中是不可变的。尝试使用stringbuilder或string.Join()方法。 – 2009-11-05 04:31:47

回答

0

试试这个:

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?

0

我会保存原始字符串的长度开始。然后,向后开始,然后减去,因为通过从最后一个词开始并回到构建起来的可能性,我会快60%以下。

一旦我知道了多久,那么只需使用StringBuilder并为新字符串构建字符串。

0
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个字符,...

+0

message = message.Substring(idx + 1,message.Length - (idx + 1))< - 可能会创建太多的临时字符串,尤其是原始邮件很大。不太可能,但是,想象一下原始字符串的大小是86KB,它足够大,可以分配到一个大对象堆中,并且只通过减去60个字符左右来创建临时字符串。是的,它太极端了,尽管:) – 2009-11-05 05:14:34

+0

所有取决于Substring是否实际创建一个副本,或者它是否只保留指向父字符串的指针(我不知道C#在这方面做了什么)。鲁本斯的答案通过保持一个起始索引而不是明确的子串避免了这个问题。 – 2009-11-05 15:02:04

+0

在C#中,字符串是不可变的,因此我认为Substring会返回一个新的字符串对象,而不是保留父字符串的指针。关于Ruben的回答,我也以同样的方式思考,但是意识到LastIndexOf(char值,int startIndex)将在从startIndex搜索时返回字符串中char值的最后一个索引,而不是startIndex。因此,你和鲁本都不可能按预期工作。 – 2009-11-05 17:51:35

6

另一个(现在的测试)样品,非常相似,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上运行了所有换行手动由“”替换。

+0

String.LastIndexOf(string value,int的startIndex)。如何保证text.Substring(offset,text.LastIndexOf(“”,MAX_WIDTH))返回少于60个字符的字符串? – 2009-11-05 05:59:10

+0

我改变了LastIndexOf(“”,offset + MAX_WIDTH);现在应该工作(仍未测试) – 2009-11-05 08:58:47

+0

@Rubens,更改不保证返回小于60个字符的字符串,因为您没有更改“文本”。假设你有10K字符串“text”以“”结尾,text.LastIndexOf(“”,offset + MAX_WIDTH)将返回最后一个“”的索引,不在60个字符的限制内。 – 2009-11-05 17:39:27

1

在正则表达式中,Match Evaluator函数(一个匿名方法)完成繁重的工作并将新大小的行存储到StringBuilder中。我们不使用Regex.Replace方法的返回值,因为我们只是使用它的Match Evaluator函数作为一个功能来完成正则表达式调用中的换行 - 仅仅是因为它太棒了,因为我认为它很酷。

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

strInput就是你要的行转换的东西。

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 

这也是值得注意的在匹配评估m.Index == bmark && m.Length >= MAX_LEN if表达式第二条件的情况下,是指作为例外条件有一个字的60个字符(或大于设定最大长度愈长) - 它在这里不会被细分,而只是单独存储在一行上 - 我想你可能想在现实世界中为这种情况创建第二个公式来连接它或什么。

+0

正则表达式可能需要调整才能正确处理标点符号,但我完成了这个示例并继续前进 - 它很灵活,并提供了另一种完成换行的方法 - 核心逻辑(在匿名方法中)只是一个有几行比作者发布的核心逻辑短,所以我认为这是一个可行的答案。这是所有支持它的东西,使它更大。 – 2009-11-05 04:54:22

+0

如果要将每个文本行捕获到集合元素或数组元素中,您可以轻松替换列表.Add(..)来代替StringBuilder.Append(..)。 – 2009-11-05 05:08:08

0

的另一个...

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; 
} 
+0

欢迎来到stackoverflow!提供示例代码的简短说明总是更好,以提高发布准确性:) – 2012-10-26 05:39:16

0

我尝试了全新的解决方案,并发现它也不太工作。我已经稍微修改了它,以使其工作。它现在适用于我,解决了我遇到的问题。谢谢。 Jim。

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); 
    } 
相关问题