2009-11-05 80 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); 
    } 
相關問題