2010-02-06 52 views
2

我有一個字符串,我想逐行閱讀,但我還需要有行分隔符字符,該StringReader.ReadLine不幸修剪(不像在紅寶石保存的地方)。什麼是最快和最健壯的方式來完成這一點?在c#中讀取一行而不修剪行分隔符

替代我一直在思考:

  • 讀取輸入字符一個字符,並檢查線路,每次
  • 分隔符使用RegExp.Split以積極的前瞻

或者我只關心行分隔符,因爲我需要知道字符串中的實際位置,分隔符可以是一個字符長度。因此,如果我可以找回字符串內的遊標的實際位置也會很好,但StringReader不具有此功能。

編輯:這是我目前的實施。文件結束是通過返回一個空字符串來指定的。

StringBuilder line = new StringBuilder(); 
int r = _input.Read(); 
while (r >= 0) 
{ 
    char c = Convert.ToChar(r); 
    line.Append(c); 
    if (c == '\n') break; 
    if (c == '\r') 
    { 
    int peek = _input.Peek(); 
    if (peek == -1) break; 
    if (Convert.ToChar(peek) != '\n') break; 
    } 
    r = _input.Read(); 
} 
return line.ToString(); 
+0

有可能是另一種選擇我的答案,但它取決於在數據的來源:它是某種形式的流,或者是源只是一個簡單的字符串? – Aaronaught 2010-02-06 23:38:55

+0

我相信他們會不一致,我不能改變輸入,這被認爲是隻讀的(克隆字符串和改變不會做,因爲我需要在原始字符串內的字符位置)。輸入是一個純字符串,但是。 – SztupY 2010-02-06 23:56:50

+0

在你對下面的Aaronaught的評論中你寫道:「設計爲與mono和.net2兼容......所以不能做出任何假設」:對於那些是唯一的行結束符,你是不是有一些有效的假設你正在解析的字符串的來源? – BillW 2010-02-07 00:18:16

回答

2

您是否擔心文件(即來自Unix/Mac或Windows)或文件中的不一致?

一個非常簡單的優化,如果你知道單個文件與本身一致應該只讀取第一行字符並找出分隔符是什麼。然後確定任何其他線的確切位置將是簡單的數學。

如果失敗了,我想我會逐個字符的路線。正則表達式看起來太「聰明」了。這聽起來像是一個複雜的功能,我認爲最重要的是讓它易於編寫,閱讀,理解和最重要的調試。


還有另一種方法可以做到這一點,如果您的數據源是流,效率會更高。不幸的是,你的評論中並沒有提到,所以你必須先創建一個;不過,我會包括解決方案,無論如何,它可能給你一些啓示:

public IEnumerable<int> GetLineStartIndices(string s) 
{ 
    yield return 0; 
    byte[] chars = Encoding.UTF8.GetBytes(s); 
    using (MemoryStream stream = new MemoryStream(chars)) 
    { 
     using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) 
     { 
      while (reader.ReadLine() != null) 
      { 
       yield return stream.Position; 
      } 
     } 
    } 
} 

這會給你回每個新行的起始位置。很明顯,你可以調整這個來做你需要的任何東西,也就是用你讀的實際線條做別的事情。

請注意,這必須創建字符串的副本來創建字節數組,所以它實際上不適用於非常大的字符串。這比char-by-char方法要好一些,不太容易出錯,所以如果字符串不是兆字節,也許值得考慮。

+0

這是爲兼容mono和.net2而設計的庫的一部分。它必須是自動防故障的,所以不能做出任何假設。 – SztupY 2010-02-07 00:03:52

0

如果您只關心位置:ReadLine()將您移動到下一行。如果您存儲下面的流的.Position,則可以在以下ReadLine()之後將其與.Position進行比較。這是您剛剛讀取的字符串的長度加上的分隔符。 分隔符的長度爲currentPosition - previousPosition - line.Length

這樣你可以很容易地發現它是1或2字節(不知道細節,但你說你只關心位置)。

+0

如何從.NET中的StringReader獲取流?我在文檔中沒有看到適當的功能。 – SztupY 2010-02-07 00:06:19

+0

Urgs。它沒有。特赦,錯過了讀者的「字符串」部分,並假設你將一個流傳遞給StreamReader。如果你能做到這一點,我的建議可能會工作,做你想做的。如果你不能這樣做,那麼這是無用的廢話,我可以刪除它。 – 2010-02-07 00:18:00

+0

請參閱Aaronaught獲取職位的方式,並查看我的建議,瞭解如何幫助您。應該(tm)做到這一點。 – 2010-02-07 00:24:38

0

File.ReadAllText將爲您提供所有文件內容。對。所有。所以你最好在使用之前檢查文件的大小。

編輯:

讀這一切,然後創建一個由線產生線的枚舉。

foreach(string line in Read("some.file")) 
{ ... } 


private IEnumerator Read(string file) 
{ 
    string buffer = File.ReadAllText() 
    for (int index=0;index<buffer.length;index++) 
    { 
     string line = ... logic to build a "line" here 
     yield return line; 
    } 

    yield break; 

} 
+0

他說輸入已經是一個字符串,所以推測它適合於內存。 – Aaronaught 2010-02-07 00:18:00

+0

我需要逐行處理它,所以閱讀它都是不行的。 – SztupY 2010-02-07 00:19:51

0
 FileStream fs = new FileStream("E:\\hh.txt", FileMode.Open, FileAccess.Read); 
     BinaryReader read = new BinaryReader(fs); 
     byte[] ch = read.ReadBytes((int)fs.Length); 
     byte[] che=new byte[(int)fs.Length]; 
     int size = (int)fs.Length,j=0; 
     for (int i =0; i <= (size-1); i++) 
     { 
      if (ch[i] != '|') 
      { 
       che[j] = ch[i]; 
       j++; 
      } 

     } 
     richTextBox1.Text = Encoding.ASCII.GetString(che); 
     read.Close(); 
     fs.Close();