I need to validate a TXT layout in C #

4

I have a TXT file where I need to validate the number of characters in each column as per the layout of each document.

Note: The documents are all in a single file *.txt

In the second column is the document type "0000,0400,0430". Each document has a different layout that has to be checked.

Layout documento 0000
Coluna 1 = 6 caracteres obrigatórios
Coluna 2 = 4 caracteres obrigatórios
Coluna 3 = 8 caracteres obrigatórios
Coluna 4 <= 100 caracteres maximo
Coluna 5 = 1 caracteres obrigatórios
Coluna 6 = 7 caracteres obrigatórios
Coluna 11 = 1 caractere ou vazio

000001|0000|00000000|ABCDFG|U|1234567|201601|201601|2|1||1|123456|1.0|1
000002|0400|123456|1|123456|2|ABCDFG|123456|1234567|1||
000003|0430|123456|1010101111|111000001|0,00|0,00|0,00|0,00||0,00|5,00|0,00|||

I have this code

class Program
{
    static void Main(string[] args)
    {
        string caminhoArquivo = "C:\Temp\Teste.txt";

        try
        {
              var consulta =
              from linha in File.ReadAllLines(caminhoArquivo)
              let clienteDados = linha.Split('|')
              where clienteDados[1] == "0000"
              select new Cliente()
              {
                  Num_Linha = clienteDados[0],
                  Reg = clienteDados[1],
                  CNPJ = clienteDados[2],
                  Nome = clienteDados[3],
              };

            foreach (var item in consulta)
            {               
                Console.WriteLine(item.Num_Linha + "|" + item.Reg + "|" + item.CNPJ + "|" + item.Nome + "|");
                Console.WriteLine(item.Num_Linha.Length == 6);
                Console.WriteLine(item.Reg.Length == 4);
                Console.WriteLine(item.CNPJ.Length == 8);
                Console.WriteLine(item.Nome.Length <= 100);
                Console.WriteLine(item.Reg);
                Console.ReadKey();
            }
        }
        catch (Exception ex)
        {

            Console.WriteLine(" Erro : " + ex.Message);
        }
    }

}

Client.class

public class Cliente
  {       
    public string CNPJ { get; set; }
    public string Nome { get; set; }
    public string Num_Linha { get; set; }
    public string Reg { get; set; }
}
    
asked by anonymous 27.06.2016 / 23:04

3 answers

3

The way is to use the NuGet FileHelpers package . It is a tool that handles these types of files, even though the lines are different.

Because the rows differ according to the 2nd column, is a multi-register case and the solution can give a little work.

My suggestion is you create a class for each document type:

[DelimitedRecord("|")]
public class Registro0000
{
    public string NumeroLinha;
    public string TipoDocumento;
    public string Campo1;
    public string Campo2;
    public string Campo3;
    ...
}

[DelimitedRecord("|")]
public class Registro0400
{
    public string NumeroLinha;
    public string TipoDocumento;
    public string Campo1;
    public string Campo2;
    public string Campo3;
    ...
}

// Escreva os demais seguindo mais ou menos este padrão.

At the time of reading this file, you need to instantiate one:

var engine = new MultiRecordEngine(typeof (Registro0000),
    typeof (Registro0400),
    typeof (Registro0430), /* Coloque aqui as demais classes */);

engine.RecordSelector = new RecordTypeSelector(CustomSelector);

var resultado = engine.ReadFile("SeuArquivo.txt");

foreach (var registro in resultado)
    Console.WriteLine(registro.ToString());

Finally, write the record picker:

private Type CustomSelector(MultiRecordEngine engine, string recordLine)
{
    if (recordLine.Length == 0)
        return null;

    switch (recordLine.Substring(7, 10)) 
    {
        case "0000":
            return typeof (Registro0000);
        case "0400":
            return typeof (Registro0400);
        case "0430":
            return typeof (Registro0430);
    }

    return null;
}
    
27.06.2016 / 23:37
2

@Britto, in an analogous situation, I used awk / gawk, with a lot of versatility. I know that the solution I'm pointing to does not comply the conditions you mention, I still think it might be useful.

#!/usr/bin/gawk -f
BEGIN{ FS="[|]"}

 $2 == "0000"  &&   v0000() { print "ok"; next }
 $2 == "0400"  &&   v0400() { print "ok"; next }
 $2 == "0430"  &&   v0430() { print "ok"; next }
                              { print NR ": invalid " $2 " record"; next }

function v0000(){               ## valida registos 0000
  return( length($1)==6   &&
          length($2)==4   &&
          length($4)<=100 &&
          length($11)<=1 )
}

function v0400(){               ## sem restrições
  return 1
}

function v0430(){
  return( length($1)==6   &&
          length($2)==4   &&
          $4 ~ /^[01]+$/ )      ## $4 contem apenas seq de "0" e "1"
}

(gawk is a tiny tool that runs on any operating system)

  • NR - registration number (line number)
  • FS - field separator
28.06.2016 / 11:49
2

@Britto There are many ways to validate the txt file that you mention, this one is one of them, it's ugly plus it works, I delete some parts to reduce size.

The method reads the file to the end, so you can put as many records as you want, for example if (xxxxxxxx.StartsWith("|xxxx|")) and go doing the validations you need.

In this part _reg0000 = reg0000.Split(delimitador, StringSplitOptions.None); it will play in the array string[] _reg0000; and according to the size you compare with the amount of columns that the | 0000 | should have.

public void valida(string path_txt)
    {
        StringReader streamReader = new StringReader(path_txt);

        string reg0000;

        string[] _reg0000;

        char[] delimitador = new char[] { '|' };

        while ((reg0000 = streamReader.ReadLine()) != null)
        {
            if (reg0000.StartsWith("|0000|"))
            {
                try
                {
                    _reg0000 = reg0000.Split(delimitador, StringSplitOptions.None);

                    // 
                    //faça aqui as validações que achar preciso, por exemplo a quantidade de colunas.
                    //
                    //
                    //
                    //

                }
                catch (Exception ex)
                {

                    throw ex;
                }
            }
        }
    }
    
28.06.2016 / 20:22