1

I really don't know why Pos keep returning 0 instead of the char ";" position in string I have to get a response of a php page which outputs a Content-Type: text/plain So one example output is 2;fulano;fulano;0 3;ciclano;ciclano;0 4;beltrano;beltrano;0 5;foo;foo;0 8;jose;jose;0 9;maria;maria;0

and the code is

var
  linha,uid,login,senha,email,tipo : WideString;
  resposta : TStringList;
  I : Integer;
begin
  try
    resposta := TStringList.Create;
    resposta.Text := frmMain.IdHTTP1.Get(frmMain.cdsConfig.FieldByName('WebService').AsString+'listdest.php');
    for I := 0 to resposta.Count-1 do
    begin
      linha := resposta.Strings[i];
      if i = 0 then
        Delete(linha,1,1); // the first line have one wierd $FEFF
      if length(linha) > 5 then
        begin

          uid := Copy(linha,1,Pos(linha,';')-1);
          Delete(linha,1,Pos(linha,';'));
          login:=Copy(linha,1,Pos(linha,';')-1);
          Delete(linha,1,Pos(linha,';'));
          senha:=Copy(linha,1,Pos(linha,';')-1);
          Delete(linha,1,Pos(linha,';'));
          email:=Copy(linha,1,Pos(linha,';')-1);
          Delete(linha,1,Pos(linha,';'));
          tipo:=Copy(linha,1,Pos(linha,';')-1);
          Delete(linha,1,Pos(linha,';'));
        end;
    end;
    //dlgWait.Close;
  except on E :Exception do
    begin
      MessageBox(Self.Handle,PWideChar(E.Message),'Erro',MB_OK+MB_ICONERROR+MB_APPLMODAL);
      dlgWait.Close;
      FreeAndNil(resposta);
    end;
  end;
Rodrigo Peetz
  • 51
  • 1
  • 5
  • In this case, I would use a `TStringList` to parse the lines, not use `Pos()` at all. Set `TStringList.Delimiter=';'` and `TStringList.StrictDelimiter=True`, then set `TStringList.DelimitedText=linha`. Or, use Indy's `Fetch()` or `SplitDelimitedString()` functions (since the question is tagged with "Indy"). And FYI, "*the first line have one wierd $FEFF*" means the text has a UTF-16 BOM in front of it, which is a bit odd for a webserver to send, instead of relying on the HTTP `Content-Type` header to carry the charset information. – Remy Lebeau Aug 21 '17 at 22:18
  • @Remy I guess it depends on how many items are expected to be parsed out. Here, it seems like there will always be 4 every time, so I'd consider it safe and faster in all senses to manually parse it like this. However, if there are many (such as 20+), or a variable (unknown) amount, then yes, certainly a `TStringList` would work great. But for only 4 values, I would think `TStringList` would be a bit too heavy for the task. – Jerry Dodge Aug 21 '17 at 22:21
  • @JerryDodge: all the more reason I would opt for using `Fetch()` before using `Pos()` – Remy Lebeau Aug 21 '17 at 22:22

1 Answers1

7

Your call to Pos is backwards. The parameters are:

function Pos(const SubStr, Str: _ShortStr; Offset: Integer): Integer;

But your code assumes they are:

function Pos(const Str, SubStr: _ShortStr; Offset: Integer): Integer;

So actually what it's trying to do is look for the value of linha within ';', which of course unless linha = ';', it will return 0.

Another way to put it, as Rudy said, instead of looking for a needle in a haystack, your code is looking for a haystack in a needle.

Swap around the first and second parameters to these calls.


On a side note, just a tip for performance. Rather than calling Pos twice for each, keep a cached copy of the value...

P := Pos(';', linha);
uid := Copy(linha,1,P-1);
Delete(linha,1,P);
Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327