2009-05-09 11 views
22

¿Hay alguna manera de leer una línea adelante para comprobar si la siguiente línea contiene datos de etiquetas específicos?¿Lees una línea de un lector de secuencias sin consumir?

Estoy tratando con un formato que tiene una etiqueta de inicio pero no una etiqueta de cierre.

Me gustaría leer una línea agréguela a una estructura y luego pruebe la línea siguiente para asegurarse de que no sea un nuevo "nodo" y si no lo está, siga agregando si está cerrado esa estructura y haga una nueva uno

la única solución que se me ocurre es tener dos lectores de flujo que van al mismo tiempo un poco suffling hay camino a lo largo el paso de bloqueo pero que parece wastefull (si se va a trabajar incluso)

necesito algo así como peek pero peekline

+0

Creo enfoque PeekLine no es una buena manera de hacer frente a "sin etiqueta de cierre" problema, porque siempre hay que mirar la línea y la prueba wherher comienza nueva estructura. Me gustaría establecer la posición de la secuencia en la línea anterior y la siguiente ReadLine devolverá la línea que ha leído. – Gqqnbig

Respuesta

26

El problema es la secuencia subyacente puede no ser buscable. Si echa un vistazo a la implementación del lector de flujo, utiliza un búfer para poder implementar TextReader.Peek() incluso si la secuencia no es buscable.

Se puede escribir un adaptador simple que lee la siguiente línea y tampones internamente, algo como esto:

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

Inicializaría 'BufferedLines' antes del uso :) y también, utilizaría otro nombre para PeekLine(), ya que el nombre sugiere que siempre devolvería la misma línea (la siguiente línea desde la posición de la última ReadLine). Votado +1 ya – tofi9

+1

Gracias agregó el inicializador. Ni siquiera compiló el código. Tal vez algo como LookAheadReadLine() podría ser más apropiado. –

+7

Expandí esto ligeramente para que la clase herede de TextReader: https: //gist.github.com/1317325 –

4

Puede almacenar la posición accediendo a StreamReader.BaseStream.Position, luego lea la línea siguiente línea, haga su prueba Y luego tratar de la posición antes de leer la línea:

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

Se trata de un montón de búsqueda y re-lectura de las mismas líneas. Usando un poco de lógica, que puede ser capaz de evitar este conjunto - por ejemplo, cuando se ve una nueva etiqueta de inicio, cerrar la estructura existente y empezar uno nuevo - aquí hay un algoritmo básico:

 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

Mirando aquí: parece que la posición de la secuencia subyacente no siempre coincide con lo que StreamReader: http: //stackoverflow.com/questions/1737591/streamreader-c-peek – Casebash

1

Por qué la dificultad? Devuelve la siguiente línea, independientemente. Compruebe si es un nuevo nodo, si no, agréguelo a la estructura. Si es así, crea una nueva estructura.

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

Esto es lo que llevo hasta ahora. Fui más de la ruta dividida que la ruta de línea por línea de lector de flujo.

Estoy seguro de que hay algunos lugares que están muriendo por ser más elegantes, pero por ahora parece estar funcionando.

Por favor, hágamelo saber lo que piensa

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 e INDI son nombres horribles para esas estructuras (si alguien más puede necesitar leer o trabajar con su código). –

+0

Ese es el nombre de la etiqueta que pensé que era bastante explicativo – Crash893

Cuestiones relacionadas