How to split a string with a pipe

I have a line with the following description: '| 0200 | 4 | SALGADOS ||| KG | 00 | 19051000 |||| 17 | '

I want to share where the pipe is to store data in the database.

I am using the pos function incorrectly. But I am getting data.

Inside if, then I insert data into db.

ReadLn(txt, line);
if True then
  if (Pos('|0200|', line)) = 1 then
  begin
    fArq.Add(line);
  end;
  if (pos('|0000|', line)) = 1 then
  begin
    fArq.Add(line);
  end;
  if (pos('|0005|', line)) = 1 then
  begin
    fArq.Add(line);
  end;
  if (pos('|C460|', line)) = 1 then
  begin
    fArq.Add(line);
    flagCF := True;
  end
  else
  begin
    if flagCF = True then
      if (pos('|C490|', line)) = 0 then
        fArq.Add(line)
      else
        flagCF := False;
  end

      

+3


source to share


5 answers


You can also use TStringList:

lStringList := TStringList.Create;
lStringList.delimiter := '|';
lStringList.DelimitedText := '|0200|4|SALGADOS|||KG|00|19051000||||17|';

      

Now you can access each field using lStringList.Items [index]




Note (from comments): If whitespace characters are included in the string, set the parameter StrictDelimiter

to true to not treat them as delimiters.

+7


source


With ExtractStrings

you can add all values ​​between | to the one who TStrings

came.

Assuming it fArq

is a descendant TStrings

:



ExtractStrings(['|'], [], PChar(line), fArq);

      

+2


source


If you are using Delphi XE3 and above, you can use the Split Helper Class.

 parts:=line.Split(['|'],TStringSplitOptions.ExcludeEmpty);

      

0


source


I have the following functions that I have been using for quite some time.

There are two options here, the first is a one-off function type, and the other is when you want to efficiently process the entire input string from the first element to the last in order.

I've also included related functions for counting the number of sections.

PS These functions are actually based on 1 as written. PPS I ripped functions from another device and didn't check this block for complete correctness. YMMV.

Non-POS methods are considered one-time use. i.e. You are looking for only one value in a given input line.

POS methods take two additional integer variables to store internal index positions for later use. The initial value of the variables must be set to -1 for the first call. After that, you should simply provide the values ​​for the next iteration of the call that was returned by the previous call.

For example.

Non-POS usage:

const
  Str1 = '|0200|4|SALGADOS|||KG|00|19051000||||17|';

.
.
.

begin
  showmessage( ParseSection(Str1, 1, '|') );  //returns 0200
  showmessage( ParseSection(Str1, 4, '|') );  //returns '' (empty string)


  //this will show every element in the string once
  Idx1 := -1;
  Idx2 := -1;
  for loop := 1 to CountSections(Str1, '|') do
    showmessage( ParseSectionPos(Str1, loop, '|', Idx1, Idx2) );  
  //Idx1 and Idx2 are self referenced variables and don't need outside intervention
  //These are necessary to obtain the best possible speed
end;

      

Other method variations allow you to define quotes and a quote symbol.

unit rmControls.Strings.Sections;

interface

uses System.Classes, System.SysUtils;

function CountSections(const ParseLine: string; const ParseSep: char): integer; overload;
function CountSections(const ParseLine: string; const ParseSep: char; const QuotedStrChar: char): integer; overload;

function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char): string; overload;
function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char): string; overload;

function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer): string; overload;
function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer): string; overload;

function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char):string; overload;
function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char):string; overload;

function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer):string; overload;
function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer):string; overload;

implementation

uses System.Math, System.Masks, System.Character, System.Variants;

function CountSections(const ParseLine: string; const ParseSep: char; const QuotedStrChar: char): integer; overload;
var
  wEnd: PChar;
  Loop: integer;
  wInQuote: boolean;
begin
  wInQuote := false;
  wEnd := PChar(ParseLine);
  result := 0;

  for Loop := 1 to Length(ParseLine) do
  begin
    if (wEnd^ = QuotedStrChar) then
      wInQuote := not wInQuote;

    if not wInQuote and (wEnd^ = ParseSep) then
      inc(result);
    inc(wEnd);
  end;
  if Length(ParseLine) <> 0 then
    inc(result);
end; { CountSections }

function CountSections(const ParseLine: string; const ParseSep: char): integer; overload;
var
  wEnd: PChar;
  Loop: integer;
begin
  wEnd := PChar(ParseLine);
  result := 0;
  for Loop := 1 to Length(ParseLine) do
  begin
    if (wEnd^ = ParseSep) then
      inc(result);
    inc(wEnd);
  end;
  if Length(ParseLine) <> 0 then
    inc(result);
end; { CountSections }

function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char): string; overload;
var
  w1, w2: integer;
begin
  w1 := -1;
  w2 := -1;
  result := ParseSectionPos(ParseLine, ParseNum, ParseSep, w1, w2);
end; { ParseSection }

function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char): string;  overload;
var
  w1, w2: integer;
begin
  w1 := -1;
  w2 := -1;
  result := ParseSectionPos(ParseLine, ParseNum, ParseSep, QuotedStrChar, w1, w2);
end; { ParseSection }

function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer): string;
var
  wStart, wEnd: PChar;
  wIndex, Loop: integer;
  wLoopIDX: integer;
begin
  wIndex := 1;
  wLoopIDX := 1;
  wEnd := PChar(ParseLine);
  if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
  begin
    inc(wEnd, FromIDX);
    wIndex := FromPOS;
    wLoopIDX := FromIDX;
  end;
  wStart := wEnd;

  for Loop := wLoopIDX to Length(ParseLine) do
  begin
    if (wEnd^ = ParseSep) then
    begin
      if wIndex = ParseNum then
        break
      else
      begin
        inc(wIndex);
        inc(wEnd);
        wStart := wEnd;
      end;
    end
    else
      inc(wEnd);
  end;

  if wIndex = ParseNum then
  begin
    SetString(result, wStart, wEnd - wStart);
    if result = #0 then
      result := '';
    FromIDX := wEnd - PChar(ParseLine);
    FromPOS := ParseNum;
  end
  else
    result := '';
end;

function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer): string;
var
  wStart, wEnd: PChar;
  wIndex, Loop: integer;
  wInQuote: boolean;
  wLoopIDX: integer;
begin
  wInQuote := false;
  wIndex := 1;
  wLoopIDX := 1;

  wEnd := PChar(ParseLine);
  if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
  begin
    inc(wEnd, FromIDX);
    wIndex := FromPOS;
    wLoopIDX := FromIDX;
  end;
  wStart := wEnd;

  for Loop := wLoopIDX to Length(ParseLine) do
  begin
    if (wEnd^ = QuotedStrChar) then
      wInQuote := not wInQuote;

    if not wInQuote and (wEnd^ = ParseSep) then
    begin
      if wIndex = ParseNum then
        break
      else
      begin
        inc(wIndex);
        inc(wEnd);
        wStart := wEnd;
      end;
    end
    else
      inc(wEnd);
  end;

  if wIndex = ParseNum then
  begin
    SetString(result, wStart, wEnd - wStart);
    if (Length(result) > 0) and (result[1] = QuotedStrChar) then
      result := AnsiDequotedStr(result, QuotedStrChar);
    if result = #0 then
      result := '';
    FromIDX := wEnd - PChar(ParseLine);
    FromPOS := ParseNum;
  end
  else
    result := '';
end;

function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char): string; overload;
var
  w1, w2: integer;
begin
  w1 := -1;
  w2 := -1;
  result := UpdateSectionPos(ParseLine, UpdateText, ParseNum, ParseSep, w1, w2);
end;

function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char): string; overload;
var
  w1, w2: integer;
begin
  w1 := -1;
  w2 := -1;
  result := UpdateSectionPos(ParseLine, UpdateText, ParseNum, ParseSep, QuotedStrChar, w1, w2);
end;

function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer):string; overload;
var
  wStart, wEnd: PChar;
  wIndex, Loop: integer;
  wLoopIDX: integer;
begin
  wIndex := 1;
  wLoopIDX := 1;
  wEnd := PChar(ParseLine);
  if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
  begin
    inc(wEnd, FromIDX);
    wIndex := FromPOS;
    wLoopIDX := FromIDX;
  end;
  wStart := wEnd;

  for Loop := wLoopIDX to Length(ParseLine) do
  begin
    if (wEnd^ = ParseSep) then
    begin
      if wIndex = ParseNum then
        break
      else
      begin
        inc(wIndex);
        inc(wEnd);
        wStart := wEnd;
      end;
    end
    else
      inc(wEnd);
  end;

  if wIndex = ParseNum then
  begin
    SetString(result, PChar(ParseLine), wStart - pChar(ParseLine));
    if result = #0 then
      result := '';
    result := result + updateText + pchar(wEnd);
    FromIDX := wEnd - PChar(ParseLine);
    FromPOS := ParseNum;
  end
  else
    raise Exception.Create('Index not found');
end;

function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer):string; overload;
var
  wStart, wEnd: PChar;
  wIndex, Loop: integer;
  wInQuote: boolean;
  wLoopIDX: integer;
begin
  wInQuote := false;
  wIndex := 1;
  wLoopIDX := 1;

  wEnd := PChar(ParseLine);
  if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
  begin
    inc(wEnd, FromIDX);
    wIndex := FromPOS;
    wLoopIDX := FromIDX;
  end;
  wStart := wEnd;

  for Loop := wLoopIDX to Length(ParseLine) do
  begin
    if (wEnd^ = QuotedStrChar) then
      wInQuote := not wInQuote;

    if not wInQuote and (wEnd^ = ParseSep) then
    begin
      if wIndex = ParseNum then
        break
      else
      begin
        inc(wIndex);
        inc(wEnd);
        wStart := wEnd;
      end;
    end
    else
      inc(wEnd);
  end;

  if wIndex = ParseNum then
  begin
    SetString(result, PChar(ParseLine), wStart - pChar(ParseLine));
    if result = #0 then
      result := '';
    result := result + AnsiQuotedStr(updateText, QuotedStrChar) + pchar(wEnd);
    FromIDX := wEnd - PChar(ParseLine);
    FromPOS := ParseNum;
  end
  else
    raise Exception.Create('Index not found');
end;

end.

      

0


source


This is where the function is used. It supports a length delimiter (for separating CRLF-delimited strings, fi) and AllowEmpty

which determines whether empty elements are omitted or returned.

function Split(const Str: string; Delim: string; AllowEmpty: Boolean): TStringDynArray;
var CurrDelim, NextDelim, CurrIdx: Integer;
begin
  if Str = '' then begin SetLength(Result, 0); Exit; end;
  CurrDelim := 1; CurrIdx := 0; SetLength(Result, 16);
  repeat
    if CurrIdx = Length(Result) then
      SetLength(Result, CurrIdx + 16);                

    NextDelim := PosEx(Delim, Str, CurrDelim);        
    if NextDelim = 0 then NextDelim := Length(Str)+1; // the end of the string
    Result[CurrIdx] := Copy(Str, CurrDelim, NextDelim - CurrDelim);
    CurrDelim := NextDelim + Length(Delim);

    if (Result[CurrIdx] <> '') or AllowEmpty
      then Inc(CurrIdx)
      else Continue;
  until CurrDelim > Length(Str);
  SetLength(Result, CurrIdx);                      // cut the array to actual length
end;

      

0


source







All Articles