Delphi - 重新拆分字符串数组?
Delphi - Re-split an array of string?
假设我有这样一个字符串:
string1 := 'me,email1,you,email2,him,email3,them,email4';
要将其转换为字符串数组,我只需执行以下操作:
array1 := SplitString(string1,',');
这很好用。
但是,我得到一个像这样的数组:
array1[0] -> me
array1[1] -> email1
array1[2] -> you
array1[3] -> email2
array1[4] -> him
array1[5] -> email3
array1[6] -> them
array1[7] -> email4
我搜索了很长时间如何用这个插入到 SQLIte 中,但是没有使用
for i:= 0 to length(array1) -1
SQLExecute('INSERT INTO table(name,email) VALUES("'+array1[i]+'","'+array1[i+1]+'"');
因为索引 0 将作为姓名插入,索引 1 作为电子邮件插入,但在下一轮,索引 1 将作为姓名插入,索引 2 作为电子邮件插入,此时索引 1 是电子邮件,索引 2 是姓名...你看到问题了吗?
我想通过将初始字符串格式更改为 :
将第一个数组重新拆分为第二个数组
string1 := 'me-email1,you-email2,him-email3,them-email4';
第一次在 ' 上拆分,第二次在 - 上拆分,以获得二维数组,但目前我似乎不了解这个概念:)
郑重声明,我使用的 Delphi RAD 是最新的,目前只有少数功能/工具可用。
你会如何插入 sql?您会保留原始字符串格式,还是将其更改为二维数组?
成对迭代:
for i := 0 to length(array1) div 2 - 1 do
SQLExecute('INSERT INTO table(name,email) VALUES("'+array1[i*2]+'","'+array1[i*2+1]+'"');
你只是不应该在这里使用 per-INSERT FOR 循环。
它不适合它,如果你的字符串有 3 或 7 或任何其他奇数个元素,这是危险的。
另外,将随机数据直接拼接到 SQL 命令中是非常不可靠和脆弱的。 http://bobby-tables.com/
您应该使用带有滑动获取器的 WHILE 循环或在每个字符串一个 FOR 循环中摆动的滴答声(有限状态机)。
var q: TQuery;
// some Query-component of any library,
// including DBX, AnyDAC/ FireDAC mORMot or any other library you would use
var sa_OK, sa_err1, sa_err2: TArray<string>;
// common preparations for both methods
q.ParamCheck := True;
q.SQL.Text := 'INSERT INTO table(name,email) VALUES( :PName, :PMail )';
q.Prepared := True;
sa_OK := TArray<string>.Create( 'me','email1','you','email2','him','email3','them','email4');
// eeeaaasy example
sa_err1 := TArray<string>.Create( 'me','email1','you','email2','him');
// check this out-of-sync error too - it can happen! you should be pre-aware!
sa_err2 := TArray<string>.Create( 'Sarah O''Connor','email1','"Bobby F. Kennedy"','email2','him'#0'again','email3');
// not the letters you expected - but they can come too
Procedure Method1_Fetcher( const sa: array of string );
var i: integer;
s: string;
function Fetched: Boolean;
begin
Result := i <= High(sa);
if Result then begin
s := sa[i];
Inc(i);
end;
end;
Begin
i := Low(sa);
while true do begin
if not Fetched then break;
q.Params[1].AsWideString := s;
if not Fetched then break;
q.Params[2].AsWideString := s;
// ...you can easily add more parameters for more columns
// if not Fetched then break;
// q.Params[3].Value := s;
// ... or you can make a loop
// FOR j := 0 to q.Params.Count - 1 DO ... q.Params[j] :=...
// only executing insert if ALL the columns were filled
q.ExecSQL;
end;
q.Transaction.CommitWork;
End;
Procedure Method2_TickTock( const sa: array of string );
var i, FSM: integer;
Begin
FSM := 0;
for i := Low(sa) to High(sa) do begin
if FSM = 0 then begin
q.ParamByName('PName').AsWideString := sa[i];
FSM := 1; // next mode of tick-tock
Continue;
end;
if FSM = 1 then begin
q.ParamByName('PMail').AsWideString := sa[i];
q.ExecSQL;
// only executing insert after the last column was filled
FSM := 0; // next mode of tick-tock
Continue;
end;
/// would only come here if we made some mistake above
/// and FSM got impossible value - so no "Continue" was executed
/// show error and exit
raise EInvalidOperation.CreateFmt('FSM = %d', [FSM]);
end;
q.Transaction.CommitWork;
End;
Procedure Method3_SimplifiedFSM( const sa: array of string );
// this method is actually are streamlined method #2
// it can be made because all our steps are TOTALLY identical
// ( sans optional insert execution )
var i, FSM: integer;
Begin
FSM := 0;
for i := Low(sa) to High(sa) do begin
q.Params[ FSM ].AsWideString := sa[i];
Inc( FSM );
if FSM >= q.Params.Count then begin
q.ExecSQL; // only after (if ) last of all columns filled!
FSM := 0;
end;
end;
q.Transaction.CommitWork;
End;
现在您可以调试 Method1(sa_OK)
或 Method2(sa_err1)
之类的调用并查看它是如何工作的以及它如何处理错误
假设我有这样一个字符串:
string1 := 'me,email1,you,email2,him,email3,them,email4';
要将其转换为字符串数组,我只需执行以下操作:
array1 := SplitString(string1,',');
这很好用。
但是,我得到一个像这样的数组:
array1[0] -> me
array1[1] -> email1
array1[2] -> you
array1[3] -> email2
array1[4] -> him
array1[5] -> email3
array1[6] -> them
array1[7] -> email4
我搜索了很长时间如何用这个插入到 SQLIte 中,但是没有使用
for i:= 0 to length(array1) -1
SQLExecute('INSERT INTO table(name,email) VALUES("'+array1[i]+'","'+array1[i+1]+'"');
因为索引 0 将作为姓名插入,索引 1 作为电子邮件插入,但在下一轮,索引 1 将作为姓名插入,索引 2 作为电子邮件插入,此时索引 1 是电子邮件,索引 2 是姓名...你看到问题了吗?
我想通过将初始字符串格式更改为 :
将第一个数组重新拆分为第二个数组string1 := 'me-email1,you-email2,him-email3,them-email4';
第一次在 ' 上拆分,第二次在 - 上拆分,以获得二维数组,但目前我似乎不了解这个概念:)
郑重声明,我使用的 Delphi RAD 是最新的,目前只有少数功能/工具可用。
你会如何插入 sql?您会保留原始字符串格式,还是将其更改为二维数组?
成对迭代:
for i := 0 to length(array1) div 2 - 1 do
SQLExecute('INSERT INTO table(name,email) VALUES("'+array1[i*2]+'","'+array1[i*2+1]+'"');
你只是不应该在这里使用 per-INSERT FOR 循环。 它不适合它,如果你的字符串有 3 或 7 或任何其他奇数个元素,这是危险的。
另外,将随机数据直接拼接到 SQL 命令中是非常不可靠和脆弱的。 http://bobby-tables.com/
您应该使用带有滑动获取器的 WHILE 循环或在每个字符串一个 FOR 循环中摆动的滴答声(有限状态机)。
var q: TQuery;
// some Query-component of any library,
// including DBX, AnyDAC/ FireDAC mORMot or any other library you would use
var sa_OK, sa_err1, sa_err2: TArray<string>;
// common preparations for both methods
q.ParamCheck := True;
q.SQL.Text := 'INSERT INTO table(name,email) VALUES( :PName, :PMail )';
q.Prepared := True;
sa_OK := TArray<string>.Create( 'me','email1','you','email2','him','email3','them','email4');
// eeeaaasy example
sa_err1 := TArray<string>.Create( 'me','email1','you','email2','him');
// check this out-of-sync error too - it can happen! you should be pre-aware!
sa_err2 := TArray<string>.Create( 'Sarah O''Connor','email1','"Bobby F. Kennedy"','email2','him'#0'again','email3');
// not the letters you expected - but they can come too
Procedure Method1_Fetcher( const sa: array of string );
var i: integer;
s: string;
function Fetched: Boolean;
begin
Result := i <= High(sa);
if Result then begin
s := sa[i];
Inc(i);
end;
end;
Begin
i := Low(sa);
while true do begin
if not Fetched then break;
q.Params[1].AsWideString := s;
if not Fetched then break;
q.Params[2].AsWideString := s;
// ...you can easily add more parameters for more columns
// if not Fetched then break;
// q.Params[3].Value := s;
// ... or you can make a loop
// FOR j := 0 to q.Params.Count - 1 DO ... q.Params[j] :=...
// only executing insert if ALL the columns were filled
q.ExecSQL;
end;
q.Transaction.CommitWork;
End;
Procedure Method2_TickTock( const sa: array of string );
var i, FSM: integer;
Begin
FSM := 0;
for i := Low(sa) to High(sa) do begin
if FSM = 0 then begin
q.ParamByName('PName').AsWideString := sa[i];
FSM := 1; // next mode of tick-tock
Continue;
end;
if FSM = 1 then begin
q.ParamByName('PMail').AsWideString := sa[i];
q.ExecSQL;
// only executing insert after the last column was filled
FSM := 0; // next mode of tick-tock
Continue;
end;
/// would only come here if we made some mistake above
/// and FSM got impossible value - so no "Continue" was executed
/// show error and exit
raise EInvalidOperation.CreateFmt('FSM = %d', [FSM]);
end;
q.Transaction.CommitWork;
End;
Procedure Method3_SimplifiedFSM( const sa: array of string );
// this method is actually are streamlined method #2
// it can be made because all our steps are TOTALLY identical
// ( sans optional insert execution )
var i, FSM: integer;
Begin
FSM := 0;
for i := Low(sa) to High(sa) do begin
q.Params[ FSM ].AsWideString := sa[i];
Inc( FSM );
if FSM >= q.Params.Count then begin
q.ExecSQL; // only after (if ) last of all columns filled!
FSM := 0;
end;
end;
q.Transaction.CommitWork;
End;
现在您可以调试 Method1(sa_OK)
或 Method2(sa_err1)
之类的调用并查看它是如何工作的以及它如何处理错误