在DB单元有一个ExtractField 函数,也是分解用分号分隔的字符串的。所以用了 ExtractFieldName这个名称。
源字符串列表如下:
A@
B@;
@
;
;@@AC
将它转换成分分号分隔的字符串, 转换的原则为:
1.如果字符串本身中有分号则用 @; 代替,@是自己定的转义字符。
2.如果字符串本身就有@字符,则用@@来代替
上面的源字符串的转换结果如下如下:
A@@;B@@@;;@@;@;;@;@@@@AC
现在要将这个字符串还原为源字符串:还原的原则为:
1. 如果遇到 @@ 则还原为 @
2. 如果遇到 @; 则还原为 ;
3. 如果遇到了单个的 @ 则保存为 @
因为 ;是分隔字符串,所以程序先开始查找 ;然后从找到的位置返向检查看它前面是不是有 @ 如果有还要检查有几个 如果结果Count是偶数个子说明这个 ;就分隔字符符,前面有Count/2 个 @ 。如果Count是奇数个@ 则说明 ;中做为字符串中的 ;号出现的,前面有 (Cout-1)/2 个 @
找到一个分隔符后将新得到字符串保存到列表中。然后将这个字符串中的 @@ 替换成 @
程序主要提高速度是靠 StrPos 和SetString
StrPos 比Pos 的速度快,返回的是找到的字符 Pchar 类型,是一个指针
SetString 从一个字符串中直接内存拷贝得到其中的一部分,比Copy 要快,因为Copy要使用重新分配一块内在做为返回值
以下代码还有可能提升的地方就是:
现在定义了变量S做为原字符串保存到列表字符串的中间变量。
如果直接能拷贝原字符串内存到列表字符串内存的话速度会更快。不知道如何实现
procedure ExtractFieldName(const Fields: string; var AStrList:TStringList);
Const
CO_ESCSTR='@'; //转义符
CO_SPACESTR=';'; //分隔符
var
AIndexBeg,AIndexEnd:PChar; //当前检查的开始/结束字符
APEnd:LongWord; //字符串的结束指针
AEscCount:Integer; //连接的转义字符的个数
AEscBeg:PChar; //连接的转义字符的开始位置
S:String;
APS:PChar;
APBegS,APEndS:LongWord; //检查分解后的字符串
begin
{分解用;分隔的字符串,将@;解释为字符串中的;号}
if Fields='' then
Exit;
AIndexBeg:=PChar(Fields);
AIndexEnd:=PChar(Fields);
APEnd:=LongWord(AIndexEnd)+Length(Fields);
While LongWord(AIndexEnd)<=APEnd do
begin
AIndexEnd:=StrPos(PChar(AIndexEnd),CO_SPACESTR); //查找字符串中的分隔符
if (Nil=AIndexEnd)or(LongWord(AIndexEnd)=APEnd) then
SetString(S,AIndexBeg,PChar(APEnd)-AIndexBeg)
else //找到了一个分隔符号 ,检查它连续的 转义 字符的个数
begin
AEscCount:=0;
AEscBeg:=AIndexEnd-1;
While (AEscBeg[0]=CO_ESCSTR) do
begin
Inc(AEscCount);
Inc(AEscBeg,-1);
end;
if Odd(AEscCount) then//奇数个,分隔符本身属于字符串的
begin
Inc(AIndexEnd);
Continue;
end
else //偶数个 是分隔符
begin
SetString(S,AIndexBeg,AIndexEnd-AIndexBeg); //保存到列表中
Inc(AIndexEnd);
AIndexBeg:=AIndexEnd;
end;
end;
// @@ 或 @; 出现 替换成 @ 或 ;
//如果只出现 @ 则做为字符串中的存在
APBegS:=LongWord(PChar(S))-1;
APS:=PChar(S);
APEndS:=LongWord(APS)+Length(S);
While LongWord(APS)<APEndS do
begin
APS:=StrPos(PChar(APS),CO_ESCSTR); //查找 @
if APS=Nil then
Break
else
begin
if (APS+1)[0] in [CO_SPACESTR,CO_ESCSTR] then
begin
Delete(S,LongWord(APS)-APBegS,1);
APEndS:=LongWord(PChar(S))+Length(S);
end;
Inc(APS,1);
end;
end;
AStrList.Add(S);
if (Nil=AIndexEnd) then
Break;
end;
end;