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) 之类的调用并查看它是如何工作的以及它如何处理错误