2009-05-09 6 views
22

Gibt es eine Möglichkeit, eine Zeile voraus zu lesen, um zu testen, ob die nächste Zeile bestimmte Tag-Daten enthält?Eine Zeile aus einem Streamreader lesen, ohne zu konsumieren?

Ich habe es mit einem Format zu tun, das ein Start-Tag, aber kein End-Tag hat.

Ich möchte eine Zeile lesen, fügen Sie es zu einer Struktur dann testen Sie die Zeile unten, um sicherzustellen, dass es nicht ein neuer "Knoten" und wenn es nicht hinzufügen, wenn es diese Struktur struct und eine neue machen eine

die einzige Lösung, die ich denken kann, ist zwei Stream Leser zur gleichen Zeit zu haben, ein bisschen dort Weg entlang Gleichschritt suffling aber das scheint wastefull (wenn es auch funktioniert)

ich brauche so etwas wie Peek aber peekline

+0

denke ich PeekLine Ansatz kein guter Weg ist mit „kein End-Tag“ Problem zu beschäftigen, denn man muss immer Linie und Test peek wherher neue Struktur beginnt. Ich möchte die Position des Streams auf die vorherige Zeile setzen und als nächstes wird ReadLine die Zeile zurückgeben, die Sie gelesen haben. – Gqqnbig

Antwort

26

Das Problem ist, der zugrunde liegende Stream ist möglicherweise nicht einmal suchbar. Wenn Sie sich die Stream-Reader-Implementierung ansehen, wird ein Puffer verwendet, um TextReader.Peek() zu implementieren, selbst wenn der Stream nicht suchbar ist.

Sie könnten einen einfachen Adapter schreiben, die nächste Zeile und Puffer intern liest, so etwas wie diese:

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

Ich würde die 'BufferedLines' vor der Verwendung :) initialisieren und Außerdem würde ich einen anderen Namen für PeekLine() verwenden, da der Name darauf hindeutet, dass immer dieselbe Zeile zurückgegeben wird (die nächste Zeile von der Position der letzten ReadLine). Voted +1 bereits – tofi9

+1

Danke den Initialisierer hinzugefügt. Niemals den Code selbst kompiliert. Vielleicht ist etwas wie LookAheadReadLine() besser geeignet. –

+7

Ich habe dies etwas erweitert, so dass die Klasse von TextReader erbt: https: //gist.github.com/1317325 –

4

Sie könnten die Position auf StreamReader.BaseStream.Position speichern, dann lesen Sie die Zeile nächste Zeile, führen Sie Ihren Test , Dann in die Position ein, bevor Sie die Zeile lesen:

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

Das ist eine Menge des Suchens und Re-Lektüre der gleichen Linien. Mit etwas Logik können Sie in der Lage sein, diese ganz zu vermeiden - zum Beispiel, wenn Sie einen neuen Tag-Start sehen, schließen Sie die vorhandene Struktur und beginnt ein neues Geschäft - hier ist ein Grundalgorithmus:

 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

Blick hier: es scheint, dass die Position des zugrunde liegenden Streams nicht immer übereinstimmen mit dem StreamReader: http: //stackoverflow.com/questions/1737591/streamreader-c-peek – Casebash

1

Warum die Schwierigkeit? Gib die nächste Zeile zurück, egal. Überprüfen Sie, ob es sich um einen neuen Knoten handelt. Wenn nicht, fügen Sie ihn der Struktur hinzu. Wenn dies der Fall ist, erstellen Sie eine neue 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

Hier ist, was ich so weit gehe. Ich ging mehr von der Split-Route als der Streamreader Zeile für Zeile Route.

Ich bin sicher, es gibt ein paar Orte, die sterben, um eleganter zu sein, aber für den Moment scheint es zu funktionieren.

Bitte lassen Sie mich wissen, was Sie denken

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 und INDI sind schreckliche Namen für diese Strukturen (wenn jemand anderes Ihren Code lesen oder mit ihm arbeiten muss). –

+0

Das ist der Name des Tags, den ich für ziemlich erklärend hielt – Crash893

Verwandte Themen