2009-05-09 12 views
22

Есть ли способ прочитать вперед одну строку, чтобы проверить, содержит ли следующая строка данные определенного тега?Чтение строки с потокового устройства без использования?

Я имею дело с форматом, который имеет начальный тег, но без конечного тега.

Я хотел бы прочитать строку, добавив ее в структуру, а затем проверить строку ниже, чтобы убедиться, что это не новый «узел», и если он не продолжает добавлять, если он закрывает эту структуру и создает новую один

единственное решение, я могу думать о том, чтобы иметь два считывателя потока, идущие в то же время своего рода suffling там путь вдоль шага замка, но это кажется wastefull (если он будет работать даже)

мне нужно что-то вроде заглядывать но peekline

+0

Я думаю PeekLine подход не является хорошим способом, чтобы иметь дело с «не конец тега» проблемы, потому что вы всегда должны выглядывать линии и тест wherher начинается новая структура. Я хотел бы установить положение потока в предыдущую строку, и следующая ReadLine вернет строку, которую вы прочитали. – Gqqnbig

ответ

26

Проблема заключается в том основной поток, возможно, даже не доступен для поиска. Если вы посмотрите на реализацию потокового считывателя, он использует буфер, чтобы он мог реализовать TextReader.Peek(), даже если поток не доступен для поиска.

Вы могли бы написать простой адаптер, который читает следующую строку и буферы его внутренне, что-то вроде этого:

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

Я бы инициализировал 'BufferedLines' перед использованием :) и Кроме того, я бы использовал другое имя для PeekLine(), так как название предполагает, что оно всегда будет возвращать одну и ту же строку (следующая строка из позиции последней ReadLine). Проголосовал +1 уже – tofi9

+1

Спасибо добавил инициализатор. Никогда даже не компилировал код. Возможно, что-то вроде LookAheadReadLine() может быть более подходящим. –

+7

Я немного расширил, чтобы класс наследовал от TextReader: https: //gist.github.com/1317325 –

4

Вы можете сохранить позицию, доступ к StreamReader.BaseStream.Position, затем прочитать строку следующей строки, выполнить свой тест , А затем обратиться к позиции, прежде чем читать строку:

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

Это много поисков и перечитывая те же строки. Используя некоторую логику, вы можете быть в состоянии избежать этого в целом - например, когда вы видите новый старт тегов, закрыть существующую структуру и начать новую - вот основной алгоритм:

 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

Оказалось, что позиция базового потока может не всегда соответствовать тому, что StreamReader: http: //stackoverflow.com/questions/1737591/streamreader-c-peek – Casebash

1

Почему трудности? Верните следующую строку, независимо. Проверьте, является ли это новым узлом, если нет, добавьте его в структуру. Если это так, создайте новую структуру.

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

Вот что я зашел так далеко. Я пошел больше с раздельным маршрутом, чем потоковая линия по линии маршрута.

Я уверен, что есть несколько мест, которые умирают, чтобы быть более изящными, но сейчас это работает.

Пожалуйста, дайте мне знать, что вы думаете

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 и INDI являются ужасными именами для этих структур (если кому-то может понадобиться прочитать или работать с вашим кодом). –

+0

Это имя тега, который я думал, что он довольно объяснительный – Crash893

 Смежные вопросы

  • Нет связанных вопросов^_^