Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Lectura de fichero errónea (https://www.clubdelphi.com/foros/showthread.php?t=93732)

DarthGomis 04-02-2019 20:23:23

Lectura de fichero errónea
 
Hola,

Estoy desarrollando una app que lea un fichero con la forma:

N:Nombre;D:0000;F:00/00/0000

Donde N: es un string, D: es un entero y F: es una fecha. (cabe destacar que el orden puede estar alterado y puede que alguna linea no esté bien escrita)

El problema reside en que el método en el cual almaceno los contenidos de la línea en una lista, al llegar al segundo ';' se revoluciona y hace cosas extrañas.

Código Delphi [-]
procedure TForm1.CreateList(fileName: string);
var
  tempLine: string;      //Line with all data
  line: TLine;           //Line with data fragmented
  cha: char;
  Data: TextFile;
  tipe: string;          //Tipe of data
  temp: string;          //temporally data to storage
  nameData: string;          //name data
  numberData: integer;       //number data
  dateData: TDateTime;
  lineData: integer;       //date data

begin
  fileList := TList.Create;
  wrongLines := 0;
  rightLines := 0;
  lineData := 1;

  AssignFile(Data, fileName);
  Reset(Data);

  while not Eof(Data) do
  begin
    while not Eoln(Data) do
    begin
      Read(Data, cha);
      //Select tipe of data
      if UpperCase(temp) = 'N:'
      then
      begin
        tipe := temp;
        temp := '';
      end
      else if UpperCase(temp) = 'D:'
      then
      begin
        tipe := temp;
        temp := '';
      end
      else if UpperCase(temp) = 'F:'
      then
      begin
        tipe := temp;
        temp := '';
      end;
      if (cha = ';') or (lineData = 3)
      then
      begin
        //ShowMessage(tipe);
        if tipe = 'N:'
        then
        begin
          try
            nameData := temp;
            temp:='';
          except
            Inc(wrongLines);
            temp:='';
            break;
          end;
        end
        else if tipe = 'D:'
        then
        begin
          try
            numberData := StrToInt(temp);
            temp:='';
          except
            Inc(wrongLines);
            temp:='';
            break;
          end;
        end
        else if tipe = 'F:'
        then
        begin
          try
            //ShowMessage(temp);
            dateData := StrToDate(temp);
            temp:='';
          except
            //ShowMessage('puto');
            Inc(wrongLines);
            temp:='';
            break;
          end;
        end
        else
        ShowMessage(IntToStr(lineData));
        Inc(lineData);
      end
      else temp := temp + cha;
      ShowMessage('Tipo: ' + tipe + #13 + 'Temp: ' + temp + #13 + 'Caracter: ' + cha
                  + #13 + 'N: ' + nameData + #13 + 'D: ' + IntToStr(numberData) + #13 +
                  'F: ' + DateToStr(dateData));
    end;
    if  not (nameData = '')
    then
    begin
      if not (numberData = 0)
      then
      begin
        if not (dateData = 0)
        then
        begin
          //ShowMessage(DateToStr(dateData));
          line := TLine.Create(nameData, numberData, dateData);
          Inc(rightLines);
          fileList.Add(line);
        end;
      end;
    end;
    nameData := '';
    numberData := 0;
    dateData := 0;
    temp := '';
    lineData := 1;
    ReadLn(Data,tempLine);
  end;
CloseFile(Data);

end;

TList es una clase creada para que me diferencie qué es cada cosa

Código Delphi [-]
TLine = class

  //Data fields of a line
  private
    n: string;      //N:
    d: integer;     //D:
    f: TDateTime;   //F:

  //Properties to read the data values
  public

    line : string;

    property NewName: string
      read n;
    property NewNumber: integer
      read d;
    property NewDate: TDateTime
      read f;

  //Constructor
  constructor  Create(const n : string;
                      const d : integer;
                      const f : TDateTime);
  end;

Sería de gran ayuda que me orientaseis un poco porque soy nuevo en delphi y no tengo mucha idea.

Neftali [Germán.Estévez] 05-02-2019 10:30:06

Hola y bienvenido al club.
Es difícil porder ayudarte sólo con el código y sin ver una muestra de datos.

Una opción que tal vez nos ayude, es que coloques un fichero de ejemplo (si es posible) o al menos una porción que simule la parte del fichero que te da problemas. De esa forma se puede ejecutar el código con los datos "problemáticos" y darte una idea para solucionarlo.

Puedes comprimir el fichero y el proyecto si lo necesitas y subirlo al mensaje. Si no te deja por permisos contacta con algún moderador/adminsitrador por privado y te ayudarán a hacerlo.

bucanero 05-02-2019 12:58:33

Hola a todos,

Para realizar la separación de los distintos campos por un separador determinado, como es este caso, a mi me gusta utilizar un TStringList por su sencillez y no necesitar utilizar otros componentes, y la forma de funcionamiento es simple:

Código Delphi [-]
var
  sl: TstringList;
  datos:string;
  i: longint;
begin
  // lista de campos en formato string, separados por un delimitador (;)
  datos := 'N:Nombre;D:0000;F:00/00/0000';
  try
    sl := TStringList.Create;
    sl.StrictDelimiter := True;
    sl.Delimiter := ';';   // delimitador de campos

    sl.DelimitedText := datos; // <-- aqui se pasan los datos
    for i := 0 to sl.count - 1 do
      MessageDlg(sl.strings[i], mtInformation, [mbOK], 0);
  finally
    // se libera el objeto
    sl.Free;
  end;

Y en tu caso en concreto prueba el siguiente código:
Código Delphi [-]
type
  // estructura de datos que se va a recuperar
  TDataRec = record
    nameData: string;          //name data
    numberData: integer;       //number data
    dateData: TDateTime;

    procedure clear;                                 //inicializa los valores
    function loadFromStrings(SL: TStrings): Boolean; //lee los valores desde una lista de strings
    function IsValidData: Boolean;                   //comprueba si los valores son validos
  end;

implementation

{ TDataRec }
procedure TDataRec.clear;
begin
  // se inicializan los datos
  nameData := '';
  numberData := 0;
  dateData := 0;
end;

function TDataRec.IsValidData: Boolean;
begin
  // aqui se realizan las comprobaciones de los datos
  Result := (nameData <> '') and
            (numberData <> 0) and
            (dateData <> 0);
end;

function TDataRec.loadFromStrings(SL: TStrings): Boolean;
var
  tipe, DataStr: string;          //Tipe of data
  APosicion, i: integer;
begin
  Result := False;
  try
    clear;
    // se recorren el numero de campos leidos
    for i := 0 to SL.Count - 1 do begin
      APosicion := Pos(':', SL.strings[i]);
      if APosicion > 0 then begin

        tipe := UpperCase(Copy(SL.strings[i], 1, APosicion));
        DataStr := Copy(SL.strings[i], APosicion + 1, Length(SL.strings[i]));

        //Select tipe of data
        if tipe = 'N:' then
          nameData := DataStr
        else if tipe = 'D:' then
          numberData := StrToInt(DataStr)
        else if tipe = 'F:' then
          dateData := StrToDate(DataStr);
      end;
    end;
    Result := IsValidData;
  except
    on E: Exception do
      MessageDlg(E.message, mtError, [mbOK], 0);
  end;
end;

y aquí el proceso del fichero:
Código Delphi [-]
procedure TForm2.Button1Click(Sender: TObject);
begin
  with OpenDialog1 do
    if execute then
    try
      memo1.lines.BeginUpdate;
      ProcessFile(FileName);
    finally
      memo1.lines.EndUpdate;
    end;
end;

function TForm2.ProcessData(const DataRec: TDataRec): boolean;
begin
  Result := false;

  /// Aqui procesas cada uno de los datos ya una vez leidos 
  with DataRec do begin
    // yo solo muestro los datos en un memo, para verificar que son correctos 
    memo1.Lines.Add(Format('N:' + #9 + '%s ' + #9 + 'D:%d ' + #9 + 'F:' + #9 + '%s', [nameData, numberData, formatdatetime('dd/mm/yyyy', dateData)]));

//    line := TLine.Create(nameData, numberData, dateData);
//    fileList.Add(line);

  end;
  Result := true;
end;

procedure TForm2.ProcessFile(const AFileName: string);
var
  TxtF: TextFile;
begin
  try
    AssignFile(TxtF, AFileName);
    Reset(TxtF);
    ParseFile(TxtF);
  finally
    CloseFile(TxtF);
  end;
end;

procedure TForm2.ParseFile(var TxtF: TextFile);
var
  tempLine: string;
  sl: TstringLIst;
  DataRec: TDataRec;
  rightLines, wrongLines, lineData: integer;       //date data
begin
  wrongLines := 0;
  rightLines := 0;
  lineData := 0;
  try
    //se crea un StringList configurado para serparar los elementos por un delimitador
    // en este caso el ";"
    sl := TStringList.Create;
    sl.StrictDelimiter := True;
    sl.Delimiter := ';';

    while not Eof(TxtF) do begin
      Readln(TxtF, tempLine);
      sl.DelimitedText := tempLine;
      inc(lineData);
      if DataRec.loadFromStrings(sl) and ProcessData(DataRec) then
        Inc(rightLines)
      else
        Inc(wrongLines);
    end;
  finally
    // se libera el objeto
    sl.Free;
  end;
end;

De esta forma aunque los campos te vengan en distinto orden los debes de poder leer sin problemas y en la validación de los datos ya puedes comprobar si te son útiles o no

Un saludo

DarthGomis 05-02-2019 19:41:48

Muchisimas graciaas, me ha servido de mucha ayuda

Un saludo


La franja horaria es GMT +2. Ahora son las 12:06:11.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi