2009-05-09 2 views
22

次の行に特定のタグデータが含まれているかどうかをテストするために1行先読みする方法はありますか?ストリームリーダから行を読み込むことなく消費しますか?

私は開始タグを持つが終了タグを持たないフォーマットを扱っています。

私は構造体に行を追加して、それを新しい "ノード"ではないことを確認するために下の行をテストし、構造体を閉じて新しい私は考えることができる1つの

唯一の解決策は、ちょっとロックステップに沿ってそこに道をsuffling同時に起こって2人のストリームの読者を持つことであるが、それは(それも動作する場合)

私がpeekようなものが必要wastefullですしかし、ピークライン

+0

聞かせください。ストリームの位置を前の行に設定したいと思います。次に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

ここまでです。私は、ストリームリーダよりも分割されたルートをラインごとに多く行きました。

私は、よりエレガントになるために死んでいるいくつかの場所があると確信していますが、今のところ働いているようです。

私はあなたが常にラインを覗いて、新しい構造が始まるwherherテストする必要があるためPeekLineのアプローチは、「なし終了タグ」の問題に対処するための良い方法はないと思う私はあなたが

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

関連する問題