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
source to share
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.
source to share
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);
source to share
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.
source to share
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;
source to share