【问题标题】:Delphi - Re-split an array of string?Delphi - 重新拆分字符串数组?
【发布时间】:2015-12-14 05:20:16
【问题描述】:

假设我有一个这样的字符串:

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 中?是保留原来的String格式,还是改成二维数组?

【问题讨论】:

  • 你真正想做的是解析成一个记录数组,每条记录都有一个名称字段和一个电子邮件字段。
  • 对于任何语言来说都是一个非常糟糕的想法。 Delphi PHP, Python - 随便!!!请使用可靠的方法! bobby-tables.com

标签: arrays sqlite delphi string-split


【解决方案1】:

成对迭代:

for i := 0 to length(array1) div 2 - 1 do
  SQLExecute('INSERT INTO table(name,email) VALUES("'+array1[i*2]+'","'+array1[i*2+1]+'"');

【讨论】:

    【解决方案2】:

    你不应该在这里使用 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) 这样的调用,看看它是如何工作的以及它如何处理错误

    【讨论】:

    • 我喜欢这个解决方案,但当时它对我来说太复杂了。感谢您抽出宝贵时间回复我,很抱歉花了这么长时间才回复。
    • 在意外和可能的恶意输入后恢复的努力会更糟......
    猜你喜欢
    • 1970-01-01
    • 2016-03-22
    • 2013-08-19
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 2011-12-20
    • 2016-08-04
    • 2014-05-16
    相关资源
    最近更新 更多