我有以下功能,我已经使用了很长一段时间了。
这里有两种变体,第一种是一次性使用类型的函数,另一种是当您想要有效地处理从第一个元素到最后一个元素的整个输入字符串时。
我还包括了相关的函数来计算部分的数量。
PS这些函数实际上是基于1的,如所写。PPS 我从另一个单元中提取了功能,并没有检查这个单元的完全正确性。YMMV。
非 POS 方法被认为是一次性功能。IE。您只是在给定的输入字符串中寻找单个值。
POS 方法采用两个加法整数变量来存储内部索引位置以供以后使用。第一次调用时,变量的初始值应设置为 -1。之后,您应该只将值提供给上一个调用返回的调用的下一次迭代。
例如。
非 POS 使用:
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;
该方法的其他变体允许用户定义引用值和引用字符。
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.