Hi all,

here is the CSV decoding function. I have a problem with the array of
string as the compiler is saying the type is not good when trying the
SetLength(a). I must create a type for this.

Now I submit this procedure (because a function cant' return an array
of string, but could probably return the type?) and I want inputs:
- a better solution for 'array of string'
- if no solution, is a function better?

Then after I received the input I'll send a patch for sysutils (when
the forum is up again).

Thank you very much (for making this code and fpc/lazarus better). :)



type
 TArrayOfString = array of string;

implementation

{ Summary:
   Decode a CSV string and return an array of string.
 Arguments:
   s = csv record (line) to parse
   a = array of string to fill (length will be set automatically)
   stringDelimiter = the string delimiter to use (usually '"')
   valueDelimiter = the value delimiter to use (usually ',')
   looseQuoting = In strick CSV the stringDelimiter must be found right after
     the valueDelimiter in order to be a valid quote. If looseQuoting is
     activated, space (#32) chars will be accepted
 Description:
   The function will parse the 's' string and fill the 'a' array of string with
   a dimension for each part of 's' delimited by valueDelimiter. If a
   stringDelimier is first found, all valueDelimiter inside it will be ignored.
 Results:
   An array is returned, having the content of each column in the CSV record.
 Notes:
   Since this function is taking a string, we can' manage the aspect of imbeded
   LF/CRLF in the CSV when reading from a file (since the function is not
   reading from the file itself).
     Also, the procedure is not intended to support improperly formed CSV
   records. It was not intended to be so. Activating looseQuoting is allowing a
   breach in CSV interpretation. Something like 'a, "b"c, d' will fail as it
   should give 'a','"b"c','d' will rather give 'a','b"c','d'.
 See also:
   EncodeCSVStr
 Author:
   Alexandre Leclerc }

procedure DecodeCSVStr(const s: string; var a: TArrayOfString; const
stringDelimiter, valueDelimiter: Char; const looseQuoting: Boolean);
var
 i: LongInt;
 pc: PChar;
 sp: Integer; //start pos when copying
 count: Integer;
 isQuoted: Boolean;

 procedure AddCSVColumn;
 begin
   SetLength(a, count+1);
   a[count] := Trim(Copy(s, sp, i-sp));
   if isQuoted then //remove double-quote and last quote char
   begin
     sp := Length(a[count]); //reuse sp temporarily for column value length
     a[count] := StringReplace(
       IfThen(a[count][sp] = stringDelimiter,
         Copy(a[count], 1, sp-1), a[count]),
       stringDelimiter + stringDelimiter, stringDelimiter, [rfReplaceAll]);
   end;
   Inc(count);
   sp := 0;
   isQuoted := False;
 end;

var
 inString: Boolean;
begin
 inString := False;
 isQuoted := False;
 pc := @s[1];
 sp := 0;
 count := 0;
 for i := 1 to Length(s) do
 begin
   if not (looseQuoting and (pc^ = #32)) then
     if pc^ = stringDelimiter then
     begin
       if sp = 0 then //string delimiter is only good at start
       begin
         isQuoted := True;
         sp := i+1;
       end;
       if isQuoted then
         inString := (not inString);
     end else
     begin
       if sp = 0 then
         sp := i;
       if (not inString) and (pc^ = valueDelimiter) then
         AddCSVColumn();
     end;
   Inc(pc);
 end;
 Inc(i);
 AddCSVColumn();
end;


--
Alexandre Leclerc

_________________________________________________________________
    To unsubscribe: mail [EMAIL PROTECTED] with
               "unsubscribe" as the Subject
  archives at http://www.lazarus.freepascal.org/mailarchives

Reply via email to