2009-05-09 25 views
22

Có cách nào để đọc trước một dòng để kiểm tra xem dòng tiếp theo có chứa dữ liệu thẻ cụ thể không?Đọc một dòng từ trình tạo luồng mà không cần tiêu thụ?

Tôi đang xử lý một định dạng có thẻ bắt đầu nhưng không có thẻ kết thúc.

Tôi muốn đọc một dòng thêm nó vào một cấu trúc sau đó kiểm tra dòng dưới đây để đảm bảo rằng nó không phải là "nút" mới và nếu nó không tiếp tục thêm nếu nó đóng tắt cấu trúc và tạo mới một

giải pháp duy nhất tôi có thể nghĩ đến là phải có hai người đọc dòng đi cùng lúc kinda suffling có cách cùng bước khóa nhưng điều đó dường wastefull (nếu nó thậm chí sẽ làm việc)

tôi cần một cái gì đó giống như cái nhìn nhưng xem trước

+0

Tôi nghĩ rằng cách tiếp cận PeekLine không phải là một cách tốt để đối phó với "không có thẻ kết thúc" vấn đề, bởi vì bạn luôn phải lén dòng và kiểm tra wherher cấu trúc mới bắt đầu. Tôi muốn thiết lập vị trí của dòng cho dòng trước và ReadLine tiếp theo sẽ trả về dòng bạn đã đọc. – Gqqnbig

Trả lời

26

Vấn đề là dòng cơ bản có thể thậm chí không thể tìm kiếm được. Nếu bạn xem xét việc triển khai trình đọc luồng, nó sử dụng bộ đệm để nó có thể thực thi TextReader.Peek() ngay cả khi luồng không tìm kiếm được.

Bạn có thể viết một bộ chuyển đổi đơn giản mà đọc dòng tiếp theo và đệm nó trong nội bộ, một cái gì đó như thế này:

public class PeekableStreamReaderAdapter 
    { 
     private StreamReader Underlying; 
     private Queue<string> BufferedLines; 

     public PeekableStreamReaderAdapter(StreamReader underlying) 
     { 
      Underlying = underlying; 
      BufferedLines = new Queue<string>(); 
     } 

     public string PeekLine() 
     { 
      string line = Underlying.ReadLine(); 
      if (line == null) 
       return null; 
      BufferedLines.Enqueue(line); 
      return line; 
     } 


     public string ReadLine() 
     { 
      if (BufferedLines.Count > 0) 
       return BufferedLines.Dequeue(); 
      return Underlying.ReadLine(); 
     } 
    } 
+2

Tôi sẽ khởi tạo 'BufferedLines' trước khi sử dụng :) và Ngoài ra, tôi muốn sử dụng một tên khác cho PeekLine(), như tên cho thấy rằng nó sẽ luôn luôn trở lại cùng một dòng (dòng tiếp theo từ vị trí của ReadLine cuối cùng). Đã bỏ phiếu +1 đã là – tofi9

+1

Cảm ơn bạn đã thêm bộ khởi tạo. Chưa bao giờ biên dịch mã. Có thể một cái gì đó giống như LookAheadReadLine() có thể phù hợp hơn. –

+7

Tôi đã mở rộng điều này một chút để lớp kế thừa từ TextReader: https: //gist.github.com/1317325 –

4

Bạn có thể lưu trữ vị trí truy cập StreamReader.BaseStream.Position, sau đó đọc dòng tiếp theo, làm bài kiểm tra của bạn , sau đó tìm đến vị trí trước khi bạn đọc dòng:

  // Peek at the next line 
      long peekPos = reader.BaseStream.Position; 
      string line = reader.ReadLine(); 

      if (line.StartsWith("<tag start>")) 
      { 
       // This is a new tag, so we reset the position 
       reader.BaseStream.Seek(pos);  

      } 
      else 
      { 
       // This is part of the same node. 
      } 

Đây là rất nhiều tìm kiếm và đọc lại cùng một dòng. Sử dụng một số logic, bạn có thể tránh điều này hoàn toàn - ví dụ, khi bạn nhìn thấy một sự khởi đầu thẻ mới, đóng các cấu trúc hiện có và bắt đầu một cái mới - đây là một thuật toán cơ bản:

 SomeStructure myStructure = null; 
     while (!reader.EndOfStream) 
     { 
      string currentLine = reader.ReadLine(); 
      if (currentLine.StartsWith("<tag start>")) 
      { 
       // Close out existing structure. 
       if (myStructure != null) 
       { 
        // Close out the existing structure. 
       } 

       // Create a new structure and add this line. 
       myStructure = new Structure();     
       // Append to myStructure. 
      } 
      else 
      { 
       // Add to the existing structure. 
       if (myStructure != null) 
       { 
        // Append to existing myStructure 
       } 
       else 
       { 
        // This means the first line was not part of a structure. 
        // Either handle this case, or throw an exception. 
       } 
      } 
     } 
+1

Nhìn ở đây: có vẻ như vị trí của luồng cơ bản có thể không phải lúc nào cũng khớp với những gì StreamReader: http: //stackoverflow.com/questions/1737591/streamreader-c-peek – Casebash

1

Tại sao những khó khăn? Trả lại dòng tiếp theo, bất kể. Kiểm tra nếu nó là một nút mới, nếu không, hãy thêm nó vào cấu trúc. Nếu có, hãy tạo cấu trúc mới.

// Not exactly C# but close enough 
Collection structs = new Collection(); 
Struct struct; 
while ((line = readline()) != null)) { 
    if (IsNode(line)) { 
     if (struct != null) structs.add(struct); 
     struct = new Struct(); 
     continue; 
    } 
    // Whatever processing you need to do 
    struct.addLine(line); 
} 
structs.add(struct); // Add the last one to the collection 

// Use your structures here 
foreach s in structs { 

} 
0

Đây là những gì tôi đi xa. Tôi đã đi nhiều hơn các tuyến đường tách hơn dòng streamreader bởi tuyến đường.

Tôi chắc chắn có một vài nơi đang chết để thanh lịch hơn nhưng hiện tại có vẻ như nó đang hoạt động.

Xin vui lòng cho tôi biết những gì bạn nghĩ

struct INDI 
    { 
     public string ID; 
     public string Name; 
     public string Sex; 
     public string BirthDay; 
     public bool Dead; 


    } 
    struct FAM 
    { 
     public string FamID; 
     public string type; 
     public string IndiID; 
    } 
    List<INDI> Individuals = new List<INDI>(); 
    List<FAM> Family = new List<FAM>(); 
    private void button1_Click(object sender, EventArgs e) 
    { 
     string path = @"C:\mostrecent.ged"; 
     ParseGedcom(path); 
    } 

    private void ParseGedcom(string path) 
    { 
     //Open path to GED file 
     StreamReader SR = new StreamReader(path); 

     //Read entire block and then plit on 0 @ for individuals and familys (no other info is needed for this instance) 
     string[] Holder = SR.ReadToEnd().Replace("0 @", "\u0646").Split('\u0646'); 

     //For each new cell in the holder array look for Individuals and familys 
     foreach (string Node in Holder) 
     { 

      //Sub Split the string on the returns to get a true block of info 
      string[] SubNode = Node.Replace("\r\n", "\r").Split('\r'); 
      //If a individual is found 
      if (SubNode[0].Contains("INDI")) 
      { 
       //Create new Structure 
       INDI I = new INDI(); 
       //Add the ID number and remove extra formating 
       I.ID = SubNode[0].Replace("@", "").Replace(" INDI", "").Trim(); 
       //Find the name remove extra formating for last name 
       I.Name = SubNode[FindIndexinArray(SubNode, "NAME")].Replace("1 NAME", "").Replace("/", "").Trim(); 
       //Find Sex and remove extra formating 
       I.Sex = SubNode[FindIndexinArray(SubNode, "SEX")].Replace("1 SEX ", "").Trim(); 

       //Deterine if there is a brithday -1 means no 
       if (FindIndexinArray(SubNode, "1 BIRT ") != -1) 
       { 
        // add birthday to Struct 
        I.BirthDay = SubNode[FindIndexinArray(SubNode, "1 BIRT ") + 1].Replace("2 DATE ", "").Trim(); 
       } 

       // deterimin if there is a death tag will return -1 if not found 
       if (FindIndexinArray(SubNode, "1 DEAT ") != -1) 
       { 
        //convert Y or N to true or false (defaults to False so no need to change unless Y is found. 
        if (SubNode[FindIndexinArray(SubNode, "1 DEAT ")].Replace("1 DEAT ", "").Trim() == "Y") 
        { 
         //set death 
         I.Dead = true; 
        } 
       } 
       //add the Struct to the list for later use 
       Individuals.Add(I); 
      } 

      // Start Family section 
      else if (SubNode[0].Contains("FAM")) 
      { 
       //grab Fam id from node early on to keep from doing it over and over 
       string FamID = SubNode[0].Replace("@ FAM", ""); 

       // Multiple children can exist for each family so this section had to be a bit more dynaimic 

       // Look at each line of node 
       foreach (string Line in SubNode) 
       { 
        // If node is HUSB 
        if (Line.Contains("1 HUSB ")) 
        { 

         FAM F = new FAM(); 
         F.FamID = FamID; 
         F.type = "PAR"; 
         F.IndiID = Line.Replace("1 HUSB ", "").Replace("@","").Trim(); 
         Family.Add(F); 
        } 
         //If node for Wife 
        else if (Line.Contains("1 WIFE ")) 
        { 
         FAM F = new FAM(); 
         F.FamID = FamID; 
         F.type = "PAR"; 
         F.IndiID = Line.Replace("1 WIFE ", "").Replace("@", "").Trim(); 
         Family.Add(F); 
        } 
         //if node for multi children 
        else if (Line.Contains("1 CHIL ")) 
        { 
         FAM F = new FAM(); 
         F.FamID = FamID; 
         F.type = "CHIL"; 
         F.IndiID = Line.Replace("1 CHIL ", "").Replace("@", ""); 
         Family.Add(F); 
        } 
       } 
      } 
     } 
    } 

    private int FindIndexinArray(string[] Arr, string search) 
    { 
     int Val = -1; 
     for (int i = 0; i < Arr.Length; i++) 
     { 
      if (Arr[i].Contains(search)) 
      { 
       Val = i; 
      } 
     } 
     return Val; 
    } 
+1

FAM và INDI là tên khủng khiếp cho những cấu trúc đó (nếu ai đó có thể cần phải đọc hoặc làm việc với mã của bạn). –

+0

Đó là tên của thẻ mà tôi nghĩ rằng nó khá là giải thích – Crash893

Các vấn đề liên quan