【问题标题】:How to separate string's with pipe如何用管道分隔字符串
【发布时间】:2014-11-03 15:43:04
【问题描述】:

我有一行描述如下:'|0200|4|SALGADOS|||KG|00|19051000||||17|'

我想将数据保存在数据库中的管道分开的地方。

我错误地使用了 pos 函数。但我正在获取数据。

在 if 然后我将数据插入到数据库中。

ReadLn(txt, line);
if True then
  if (Pos('|0200|', line)) = 1 then
  begin
    fArq.Add(line);
  end;
  if (pos('|0000|', line)) = 1 then
  begin
    fArq.Add(line);
  end;
  if (pos('|0005|', line)) = 1 then
  begin
    fArq.Add(line);
  end;
  if (pos('|C460|', line)) = 1 then
  begin
    fArq.Add(line);
    flagCF := True;
  end
  else
  begin
    if flagCF = True then
      if (pos('|C490|', line)) = 0 then
        fArq.Add(line)
      else
        flagCF := False;
  end

【问题讨论】:

  • 我不明白。你指的是什么管道?顺便说一句,您可以为每个 if 块添加 else,因为一旦找到匹配项,就没有其他匹配项了。
  • @TLama:我认为 OP 的意思是“竖条”符号,这里通常称为“管道”符号,ymmv。
  • @MartynA,哦,谢谢。我立刻想到了一些数据库管道。

标签: delphi delphi-xe7


【解决方案1】:

你也可以使用TStringList:

lStringList := TStringList.Create;
lStringList.delimiter := '|';
lStringList.DelimitedText := '|0200|4|SALGADOS|||KG|00|19051000||||17|';

现在您可以使用 lStringList.Items[ index ] 访问每个字段


注意(来自 cmets):如果字符串中包含空格字符,请将 StrictDelimiter 设置为 true 以避免将它们视为分隔符。

【讨论】:

  • SplitString 也可以在这里工作(不会忽略空字符)。或者只是 Line.Split(['|']) 使用字符串助手。
  • 如果你使用DelimitedText,别忘了将StrictDelimiter设置为true。
  • 是的,如果分隔文本中可以出现空格,那么 StrictDelimiter 应该设置为 true。
  • 抱歉我的无知,但我找不到提取项目的方法。 lStringList.Items[索引]。这个功能对我来说不存在。我正在尝试操纵 cont。
  • 索引是一个数字。 lStringList.Items[0] 是第一个元素,lStringList.Items[1] 是第二个元素,直到最后一个元素 lStringList.Items[lStringList.Count-1]。
【解决方案2】:

使用ExtractStrings,您可以将| 之间的所有值添加到TStrings-descendant。

假设fArqTStrings 的后代:

ExtractStrings(['|'], [], PChar(line), fArq);

【讨论】:

  • 请注意,ExtractStrings 不会存储空字符串。所以如果你必须知道上例中的“KG”在第7位,这可能不适合你。
  • @PabloRicardo:最好避免使用“for”。您收到的任何一个答案都比尝试自己解析数据要好 - 更快得到正确,更不容易出错并且更容易维护/应用于其他数据。
  • @DaleM +1 没错。但这种特定的功能也可能是可取的。
【解决方案3】:

如果您使用 Delphi XE3 及更高版本,您可以使用 Split 类帮助方法。

 parts:=line.Split(['|'],TStringSplitOptions.ExcludeEmpty);

【讨论】:

    【解决方案4】:

    以下功能我已经使用了很长时间了。

    这里有两种变体,第一种是一次性使用类型的函数,另一种是当您想要有效地处理从第一个元素到最后一个元素的整个输入字符串时。

    我还包括了相关的功能来计算节的数量。

    附:正如所写,这些函数实际上是基于 1 的。 附言我从另一个单元中提取了功能,并且没有检查这个单元的完全正确性。 YMMV。

    非 POS 方法被视为一次性功能。 IE。您只是在给定的输入字符串中查找单个值。

    POS 方法采用两个加法整数变量来存储内部索引位置以供以后使用。第一次调用时,变量的初始值应设置为 -1。之后,您应该只将值提供给上一个调用返回的调用的下一次迭代。

    例如。

    非 POS 使用:

    const
      Str1 = '|0200|4|SALGADOS|||KG|00|19051000||||17|';
    
    .
    .
    .
    
    begin
      showmessage( ParseSection(Str1, 1, '|') );  //returns 0200
      showmessage( ParseSection(Str1, 4, '|') );  //returns '' (empty string)
    
    
      //this will show every element in the string once
      Idx1 := -1;
      Idx2 := -1;
      for loop := 1 to CountSections(Str1, '|') do
        showmessage( ParseSectionPos(Str1, loop, '|', Idx1, Idx2) );  
      //Idx1 and Idx2 are self referenced variables and don't need outside intervention
      //These are necessary to obtain the best possible speed
    end;
    

    这些方法的其他变体允许用户定义引用值和引用字符。

    unit rmControls.Strings.Sections;
    
    interface
    
    uses System.Classes, System.SysUtils;
    
    function CountSections(const ParseLine: string; const ParseSep: char): integer; overload;
    function CountSections(const ParseLine: string; const ParseSep: char; const QuotedStrChar: char): integer; overload;
    
    function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char): string; overload;
    function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char): string; overload;
    
    function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer): string; overload;
    function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer): string; overload;
    
    function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char):string; overload;
    function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char):string; overload;
    
    function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer):string; overload;
    function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer):string; overload;
    
    implementation
    
    uses System.Math, System.Masks, System.Character, System.Variants;
    
    function CountSections(const ParseLine: string; const ParseSep: char; const QuotedStrChar: char): integer; overload;
    var
      wEnd: PChar;
      Loop: integer;
      wInQuote: boolean;
    begin
      wInQuote := false;
      wEnd := PChar(ParseLine);
      result := 0;
    
      for Loop := 1 to Length(ParseLine) do
      begin
        if (wEnd^ = QuotedStrChar) then
          wInQuote := not wInQuote;
    
        if not wInQuote and (wEnd^ = ParseSep) then
          inc(result);
        inc(wEnd);
      end;
      if Length(ParseLine) <> 0 then
        inc(result);
    end; { CountSections }
    
    function CountSections(const ParseLine: string; const ParseSep: char): integer; overload;
    var
      wEnd: PChar;
      Loop: integer;
    begin
      wEnd := PChar(ParseLine);
      result := 0;
      for Loop := 1 to Length(ParseLine) do
      begin
        if (wEnd^ = ParseSep) then
          inc(result);
        inc(wEnd);
      end;
      if Length(ParseLine) <> 0 then
        inc(result);
    end; { CountSections }
    
    function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char): string; overload;
    var
      w1, w2: integer;
    begin
      w1 := -1;
      w2 := -1;
      result := ParseSectionPos(ParseLine, ParseNum, ParseSep, w1, w2);
    end; { ParseSection }
    
    function ParseSection(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char): string;  overload;
    var
      w1, w2: integer;
    begin
      w1 := -1;
      w2 := -1;
      result := ParseSectionPos(ParseLine, ParseNum, ParseSep, QuotedStrChar, w1, w2);
    end; { ParseSection }
    
    function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer): string;
    var
      wStart, wEnd: PChar;
      wIndex, Loop: integer;
      wLoopIDX: integer;
    begin
      wIndex := 1;
      wLoopIDX := 1;
      wEnd := PChar(ParseLine);
      if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
      begin
        inc(wEnd, FromIDX);
        wIndex := FromPOS;
        wLoopIDX := FromIDX;
      end;
      wStart := wEnd;
    
      for Loop := wLoopIDX to Length(ParseLine) do
      begin
        if (wEnd^ = ParseSep) then
        begin
          if wIndex = ParseNum then
            break
          else
          begin
            inc(wIndex);
            inc(wEnd);
            wStart := wEnd;
          end;
        end
        else
          inc(wEnd);
      end;
    
      if wIndex = ParseNum then
      begin
        SetString(result, wStart, wEnd - wStart);
        if result = #0 then
          result := '';
        FromIDX := wEnd - PChar(ParseLine);
        FromPOS := ParseNum;
      end
      else
        result := '';
    end;
    
    function ParseSectionPos(const ParseLine: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer): string;
    var
      wStart, wEnd: PChar;
      wIndex, Loop: integer;
      wInQuote: boolean;
      wLoopIDX: integer;
    begin
      wInQuote := false;
      wIndex := 1;
      wLoopIDX := 1;
    
      wEnd := PChar(ParseLine);
      if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
      begin
        inc(wEnd, FromIDX);
        wIndex := FromPOS;
        wLoopIDX := FromIDX;
      end;
      wStart := wEnd;
    
      for Loop := wLoopIDX to Length(ParseLine) do
      begin
        if (wEnd^ = QuotedStrChar) then
          wInQuote := not wInQuote;
    
        if not wInQuote and (wEnd^ = ParseSep) then
        begin
          if wIndex = ParseNum then
            break
          else
          begin
            inc(wIndex);
            inc(wEnd);
            wStart := wEnd;
          end;
        end
        else
          inc(wEnd);
      end;
    
      if wIndex = ParseNum then
      begin
        SetString(result, wStart, wEnd - wStart);
        if (Length(result) > 0) and (result[1] = QuotedStrChar) then
          result := AnsiDequotedStr(result, QuotedStrChar);
        if result = #0 then
          result := '';
        FromIDX := wEnd - PChar(ParseLine);
        FromPOS := ParseNum;
      end
      else
        result := '';
    end;
    
    function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char): string; overload;
    var
      w1, w2: integer;
    begin
      w1 := -1;
      w2 := -1;
      result := UpdateSectionPos(ParseLine, UpdateText, ParseNum, ParseSep, w1, w2);
    end;
    
    function UpdateSection(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char): string; overload;
    var
      w1, w2: integer;
    begin
      w1 := -1;
      w2 := -1;
      result := UpdateSectionPos(ParseLine, UpdateText, ParseNum, ParseSep, QuotedStrChar, w1, w2);
    end;
    
    function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; var FromIDX, FromPOS: integer):string; overload;
    var
      wStart, wEnd: PChar;
      wIndex, Loop: integer;
      wLoopIDX: integer;
    begin
      wIndex := 1;
      wLoopIDX := 1;
      wEnd := PChar(ParseLine);
      if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
      begin
        inc(wEnd, FromIDX);
        wIndex := FromPOS;
        wLoopIDX := FromIDX;
      end;
      wStart := wEnd;
    
      for Loop := wLoopIDX to Length(ParseLine) do
      begin
        if (wEnd^ = ParseSep) then
        begin
          if wIndex = ParseNum then
            break
          else
          begin
            inc(wIndex);
            inc(wEnd);
            wStart := wEnd;
          end;
        end
        else
          inc(wEnd);
      end;
    
      if wIndex = ParseNum then
      begin
        SetString(result, PChar(ParseLine), wStart - pChar(ParseLine));
        if result = #0 then
          result := '';
        result := result + updateText + pchar(wEnd);
        FromIDX := wEnd - PChar(ParseLine);
        FromPOS := ParseNum;
      end
      else
        raise Exception.Create('Index not found');
    end;
    
    function UpdateSectionPos(const ParseLine, UpdateText: string; ParseNum: integer; const ParseSep: char; const QuotedStrChar: char; var FromIDX, FromPOS: integer):string; overload;
    var
      wStart, wEnd: PChar;
      wIndex, Loop: integer;
      wInQuote: boolean;
      wLoopIDX: integer;
    begin
      wInQuote := false;
      wIndex := 1;
      wLoopIDX := 1;
    
      wEnd := PChar(ParseLine);
      if (FromIDX > -1) and (FromIDX < Length(ParseLine)) then
      begin
        inc(wEnd, FromIDX);
        wIndex := FromPOS;
        wLoopIDX := FromIDX;
      end;
      wStart := wEnd;
    
      for Loop := wLoopIDX to Length(ParseLine) do
      begin
        if (wEnd^ = QuotedStrChar) then
          wInQuote := not wInQuote;
    
        if not wInQuote and (wEnd^ = ParseSep) then
        begin
          if wIndex = ParseNum then
            break
          else
          begin
            inc(wIndex);
            inc(wEnd);
            wStart := wEnd;
          end;
        end
        else
          inc(wEnd);
      end;
    
      if wIndex = ParseNum then
      begin
        SetString(result, PChar(ParseLine), wStart - pChar(ParseLine));
        if result = #0 then
          result := '';
        result := result + AnsiQuotedStr(updateText, QuotedStrChar) + pchar(wEnd);
        FromIDX := wEnd - PChar(ParseLine);
        FromPOS := ParseNum;
      end
      else
        raise Exception.Create('Index not found');
    end;
    
    end.
    

    【讨论】:

      【解决方案5】:

      这是我使用的功能。它支持任意长度的分隔符(用于分割 CRLF 分隔的字符串,f.i.)和AllowEmpty 参数,用于确定是否会省略或返回空元素。

      function Split(const Str: string; Delim: string; AllowEmpty: Boolean): TStringDynArray;
      var CurrDelim, NextDelim, CurrIdx: Integer;
      begin
        if Str = '' then begin SetLength(Result, 0); Exit; end;
        CurrDelim := 1; CurrIdx := 0; SetLength(Result, 16);
        repeat
          if CurrIdx = Length(Result) then
            SetLength(Result, CurrIdx + 16);                
      
          NextDelim := PosEx(Delim, Str, CurrDelim);        
          if NextDelim = 0 then NextDelim := Length(Str)+1; // the end of the string
          Result[CurrIdx] := Copy(Str, CurrDelim, NextDelim - CurrDelim);
          CurrDelim := NextDelim + Length(Delim);
      
          if (Result[CurrIdx] <> '') or AllowEmpty
            then Inc(CurrIdx)
            else Continue;
        until CurrDelim > Length(Str);
        SetLength(Result, CurrIdx);                      // cut the array to actual length
      end;
      

      【讨论】:

        猜你喜欢
        • 2012-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-19
        • 2010-09-14
        • 2021-10-10
        • 1970-01-01
        相关资源
        最近更新 更多