2009-05-09 13 views
22

Czy istnieje sposób na odczytanie z wyprzedzeniem jednej linii, aby sprawdzić, czy następny wiersz zawiera określone dane znaczników?Czytanie linii z przeglądarki strumieniowej bez zużywania?

Mam do czynienia z formatem, który ma tag początkowy, ale bez tagu końcowego.

Chciałbym przeczytać linię, dodać ją do struktury, a następnie przetestować poniższy wiersz, aby upewnić się, że nie jest to nowy "węzeł" i czy nie jest dodawana, jeśli jest blisko tej struktury i utworzyć nowy jeden

jedynym rozwiązaniem mogę myśleć jest mieć dwa czytniki strumieniowych wykraczających jednocześnie trochę suffling tam droga wzdłuż kroku blokady ale wydaje wastefull (jeśli będzie to nawet działa)

muszę coś jak Peek ale peekline

+0

myślę podejście PeekLine nie jest dobrym sposobem radzenia sobie z „No tag end” problem, ponieważ zawsze trzeba zerknąć linii i testu wherher zaczyna się nowa struktura. Chciałbym ustawić pozycję strumienia na poprzednią linię, a następna ReadLine zwróci odczytaną linię. – Gqqnbig

Odpowiedz

26

Problemem jest to, podstawowy strumień może nie być widoczny. Jeśli przyjrzeć się implementacji czytnika strumieni, to używa bufora, aby mógł zaimplementować TextReader.Peek(), nawet jeśli strumień nie jest dostępny.

Mogłeś napisać prosty adapter, który odczytuje następną linię i bufory wewnętrznie, coś takiego:

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

Zainicjowałbym 'BufferedLines' przed użyciem :) i również użyłbym innej nazwy dla PeekLine(), ponieważ nazwa sugeruje, że zawsze zwróci tę samą linię (następna linia z pozycji ostatniej ReadLine). Głosowało +1 już – tofi9

+1

Dzięki dodałem inicjator. Nigdy nawet nie skompilowałem kodu. Może coś w rodzaju LookAheadReadLine() może być bardziej odpowiednie. –

+7

Rozszerzyłem to nieco, więc klasa dziedziczy po TextReader: https: //gist.github.com/1317325 –

4

Możesz przechowywać pozycję uzyskiwania dostępu do StreamReader.BaseStream.Position, a następnie przeczytaj wiersz następnej linii, wykonaj test , a następnie poszukaj pozycji przed przeczytaniem wiersza:

  // 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. 
      } 

Jest to dużo poszukiwania i ponownego czytania tych samych linii. Korzystanie z pewnej logiki, może być w stanie uniknąć tego w ogóle - na przykład, gdy pojawi się nowy początek znacznika, zamknąć istniejącą strukturę i rozpocząć nowy - oto podstawowy algorytm:

 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

Patrząc tutaj: wydaje się, że pozycja strumienia bazowego nie zawsze pasuje do StreamReadera: http: //stackoverflow.com/questions/1737591/streamreader-c-peek – Casebash

1

Dlaczego trudność? Wróć do następnej linii, niezależnie. Sprawdź, czy jest to nowy węzeł, jeśli nie, dodaj go do struktury. Jeśli tak, utwórz nową strukturę.

// 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

Oto, do czego dążę tak daleko. Przeszedłem większą część podzielonej trasy niż linia streamreader po linii.

Jestem pewien, że jest kilka miejsc, które umierają, by być bardziej eleganckimi, ale na razie wydaje się, że działają.

Proszę dać mi znać, co myślisz

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 i INDI to straszne nazwy dla tych struktur (jeśli ktoś może potrzebować czytać lub pracować z twoim kodem). –

+0

To jest nazwa tagu, który myślałem, że to było dość wyjaśniające – Crash893

Powiązane problemy