TStringList 常用方法與屬性 & DelimitedText空格問題 驗證有效

NO IMAGE

測試同事幫反映了我們程式在處理委託時的一個問題:對於港股的委託,我們對它的成交回報中股票程式碼是空的。

加日誌找到原因在這裡,港股的委託其股票程式碼是5位,會左補一個空格,而在delphi中,對於TStringList 進行類似雜湊表操作時,DelimitedText會自動判斷空格並跳過。

導致reqtext.securityid一直為空,在後續的處理中出錯。

function MakePTReqtext(reqtext: PTReqtext; sReqtext:string):Boolean;            //902
var
Hash: THashedStringList;
a : TStringList;
fixPkg : TFixPackage;
Buffer : string;
begin
Hash := THashedStringList.Create;
Buffer := Trim(sReqtext);
Hash.DelimitedText := Buffer;
Hash.Delimiter := SOH;
reqtext.MsgType := Hash.Values['35'];
reqtext.IOIID := Hash.Values['23'];
reqtext.IOITransType := Hash.Values['28'];
reqtext.IOIRefID := Getbuff2(Hash.Values['26']);
reqtext.clordid := Hash.Values['11'];
reqtext.OrigClOrdID := Getbuff2(Hash.Values['41']);
reqtext.securityid := Hash.Values['48'];                  
Simulator.AddLog(1,'解包reqtext.securityid為'    reqtext.securityid);//對於港股的股票程式碼是5位,會左補空格,此處就會取空。
reqtext.price := Getbuff(Hash.Values['44']);
reqtext.orderqty := Getbuff(Hash.Values['38']);
reqtext.side := Hash.Values['54'];
reqtext.stockholder := GetGroupValue2(Hash,const_NoPartyIDs, 5);;
reqtext.reportseat := GetGroupValue2(Hash,const_NoPartyIDs, 1);
reqtext.branchcode := GetGroupValue2(Hash,const_NoPartyIDs, 4001);
reqtext.text := Hash.Values['58'];
reqtext.UnderlyingSecurityID := Hash.Values['308'];
reqtext.orderSrc :=  Hash.Values['10901'];
reqtext.PositionEffect :=  Hash.Values['77'];
reqtext.OrdType :=  Hash.Values['40'];
reqtext.TimeInForce :=  Hash.Values['59'];
reqtext.CoveredOrUncovered :=  Hash.Values['203'];
reqtext.OwnerType := Getbuff(Hash.Values['522']);
reqtext.NoDates := Getbuff(Hash.Values['580']);
reqtext.QuoteReqID := Hash.Values['131'];
reqtext.PartyID := Hash.Values['448']; 
reqtext.SecondaryOrderID := Trim(Hash.Values['198']);
if reqtext.SecondaryOrderID = '0' then
reqtext.SecondaryOrderID := '';
reqtext.GroupLeges := GetGroupLegesValue2(Hash);
Hash.Free;
Result := True;
end;

網上找到對於這個問題的解釋及解決方法:

TStringList 常用方法與屬性&DelimitedText空格問題
//TStringList 常用方法與屬性:
var
List: TStringList;
i: Integer;
begin
List := TStringList.Create;
List.Add('Strings1');           {新增}
List.Add('Strings2');
List.Exchange(0,1);             {置換}
List.Insert(0,'Strings3');      {插入}
i := List.IndexOf('Strings1'); {第一次出現的位置}
List.Sort;                      {排序}
List.Sorted := True;   {指定排序}
List.Count;                     {總數}
List.Text;                      {文字集合}
List.Delete(0);                 {刪除, 0是第一個資料}
List.LoadFromFile('c:/tmp.txt');{開啟}
List.SaveToFile('c:/tmp.txt'); {儲存}
List.Clear;                     {清空}
List.Free;                      {釋放}
end;
//讀入字串
var
List: TStringList;
begin
List := TStringList.Create;
List.CommaText := 'aaa,bbb,ccc,ddd';
//相當於: List.Text := 'aaa'   #13#10   'bbb'   #13#10'   'ccc'   '#13#10'   'ddd';
ShowMessage(IntToStr(List.Count)); //4
ShowMessage(List[0]); //aaa
List.Free;
end;
//置換分隔符
var
List: TStringList;
begin
List := TStringList.Create;
List.Delimiter := '|';
List.DelimitedText := 'aaa|bbb|ccc|ddd';
ShowMessage(IntToStr(List.Count)); //4
ShowMessage(List[0]); //aaa
List.Free;
end;
//類似的雜湊表操作法
var
List: TStringList;
begin
List := TStringList.Create;
List.Add('aaa=111');
List.Add('bbb=222');
List.Add('ccc=333');
List.Add('ddd=444');
ShowMessage(List.Names[1]); //bbb
ShowMessage(List.ValueFromIndex[1]); //222
ShowMessage(List.Values['bbb']); //222
//ValueFromIndex 可以賦值:
List.ValueFromIndex[1] := '2';
ShowMessage(List[1]); //bbb=2
//可以通過 Values 賦值:
List.Values['bbb'] := '22';
ShowMessage(List[1]); //bbb=22
List.Free;
end;
//避免重複值
var
List: TStringList;
begin
List := TStringList.Create;
List.Add('aaa');
List.Sorted := True; //需要先指定排序
List.Duplicates := dupIgnore; //如有重複值則放棄
List.Add('aaa');
ShowMessage(List.Text); //aaa
//Duplicates 有3個可選值:
//dupIgnore: 放棄;
//dupAccept: 結束;
//dupError: 提示錯誤.
List.Free;
end;
//排序與倒排序
{排序函式}
function DescCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := -AnsiCompareText(List[Index1], List[Index2]);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
List: TStringList;
begin
List := TStringList.Create;
List.Add('bbb');
List.Add('ccc');
List.Add('aaa');
//未排序
ShowMessage(List.Text); //bbb ccc aaa
//排序
List.Sort;
ShowMessage(List.Text); //aaa bbb ccc
//倒排序
List.CustomSort(DescCompareStrings); //呼叫排序函式
ShowMessage(List.Text); //ccc bbb aaa
//假如:
List.Sorted := True;
List.Add('999');
List.Add('000');
List.Add('zzz');
ShowMessage(List.Text); //000 999 aaa bbb ccc zzz
end;
DelimitedText空格
DelimitedText 空格也預設為分割符的原因很簡單: 
Borland的程式設計師把這個屬性對應的write方法中的一行程式碼多加了一個空格。
2種方法解決這個問題。
空格問題的解決方法之一:
先StringReplace用一個特殊字元替代空格,然後StringReplace回來
ss:='aa|bb c| c';
ss:= StringReplace(ss,' ','#',[rfReplaceAll]);
s:= TStringList.Create;
s.Delimiter:= '|';
s.DelimitedText:= ss;
for i:= 0 to s.Count - 1 do
begin
s[i]:= StringReplace(s[i],'#',' ',[rfReplaceAll]);
memo1.Lines.Add(s[i]);
end;
空格問題的解決方法之二:
找到 {DelphiInstDir}/source/Win32/rtl/common/Classes.pas 檔案,知道SetDelimitedText函式。如下所示:
注:{DelphiInstDir}為Delphi安裝目錄
procedure TStrings.SetDelimitedText(const Value: string); 
var 
P, P1: PChar; 
S: string; 
begin 
BeginUpdate; 
try 
Clear; 
P := PChar(Value); 
while P^ in [#1..' '] do 
{$IFDEF MSWINDOWS} 
P := CharNext(P); 
{$ELSE} 
Inc(P); 
{$ENDIF} 
while P^ <> #0 do 
begin 
if P^ = QuoteChar then 
S := AnsiExtractQuotedStr(P, QuoteChar) 
else 
begin 
P1 := P; 
// while (P^ > ' ') and (P^ <> Delimiter) do //原始碼
while (P^ >= ' ') and (P^ <> Delimiter) do     //修改後的程式碼  請繼續往下看
<span style="color:#6633ff;">為方便攜帶,可將Classes.pas 檔案重新編譯到你的工程檔案中即可。步驟:工程-新增到工程-Classes.pas</span>

提醒注意:

對於解決方法2,網上有別的文章寫修改後的程式碼應該是改成(p^ > ”),驗證了那樣是不可以的,應該用>=’ ‘,

因為這裡是對ASCII碼比較大小,大於空格’ ‘的都是能顯示的,應該判斷為大於等於空格。