Delphi从字符串中提取数字

时间:2012-01-11 16:56:12

标签: string delphi extract

我有各种各样的字符串,我需要使用它们,它们包含字母和数字,我试图从字符串中提取数字(这是我需要的部分),字符串将具有类似的格式 -

这只猫可以算上123 567,所以狗可以“

数字的长度和位置可能不同 12 34 123 456 1234 5678 11111 11111

此号码分隔符也可能与空格问号和短划线不同 12-34 12.34 所以字符串可能是EG“猫不能算,狗可以12-67”或“猫可以算1234.5678这样可以狗” 在Delphi中有什么聪明的方法可以提取数字吗?或者我必须通过扫描代码中的字符串来完成它。

任何帮助将不胜感激

由于

科林

4 个答案:

答案 0 :(得分:11)

如果您使用Delphi XE或更高版本,则可以使用正则表达式。根据David Heffernan的回答,这是完全未经测试的:

function ExtractNumbers(const s: string): TArray<string>;
var
    regex: TRegEx;
    match: TMatch;
    matches: TMatchCollection;
    i: Integer;
begin
    Result := nil;
    i := 0;
    regex := TRegEx.Create("\d+");
    matches := regex.Matches(s);
    if matches.Count > 0 then
    begin
        SetLength(Result, matches.Count);
        for match in matches do
        begin
            Result[i] := match.Value;
            Inc(i);
        end;
    end;
end;

答案 1 :(得分:7)

我认为这个功能正是你要找的:

function ExtractNumbers(const s: string): TArray<string>;
var
  i, ItemIndex: Integer;
  LastCharWasDigit: Boolean;
  len: Integer;
  Count: Integer;
  Start: Integer;
begin
  len := Length(s);
  if len=0 then begin
    Result := nil;
    exit;
  end;

  Count := 0;
  LastCharWasDigit := False;
  for i := 1 to len do begin
    if TCharacter.IsDigit(s[i]) then begin
      LastCharWasDigit := True;
    end else if LastCharWasDigit then begin
      inc(Count);
      LastCharWasDigit := False;
    end;
  end;
  if LastCharWasDigit then begin
    inc(Count);
  end;

  SetLength(Result, Count);
  ItemIndex := 0;
  Start := 0;
  for i := 1 to len do begin
    if TCharacter.IsDigit(s[i]) then begin
      if Start=0 then begin
        Start := i;
      end;
    end else begin
      if Start<>0 then begin
        Result[ItemIndex] := Copy(s, Start, i-Start);
        inc(ItemIndex);
        Start := 0;
      end;
    end;
  end;
  if Start<>0 then begin
    Result[ItemIndex] := Copy(s, Start, len);
  end;
end;

答案 2 :(得分:2)

function ExtractNumberInString ( sChaine: String ): String ;
var
    i: Integer ;
begin
    Result := '' ;
    for i := 1 to length( sChaine ) do
    begin
        if sChaine[ i ] in ['0'..'9'] then
        Result := Result + sChaine[ i ] ;
    end ;
end ;

答案 3 :(得分:0)

EDIT 1.: 下面的函数将读取字符串 S 中位置 Start 之后的第一个浮点数,并将其结束位置注册为 Last。此函数不适用于浮点数的不同情况,例如:

  • 3.1415926535897932384d0; Pi的双格式近似

  • 3.010299957f-1; Log2,单一格式

  • -0.000000001s9 e^(i*Pi),短格式

  • 0.0s0;短格式的浮点零

  • 0s0;也是一个短格式的浮点零

https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node19.html

function ExtractFloatStr(Start : integer; S : string; var Last : integer) : string;
var
  i, Lstr : integer;
  chln : char;
  str_acm : string;
  Numeric, Sign, DeciSep, Exponent : boolean;
begin
  Numeric := False;  Sign := False;  DeciSep := False;  Exponent := False;
  Lstr := length(S);

  If (Start > 0) and (Start <= Lstr) then
    i := Start-1
  Else i := 0;

  Last := -1;  chln := #0;
  str_acm := '';
  repeat
  begin
    i := i + 1;
    chln := S[i];
    //ShowMessage('str_acm['+IntToStr(i)+'] = '+str_acm+'P');
    If Last = -1 then
    begin

      If chln = '-' then
      begin
        { Signs will only count if they are the first element }
        If (str_acm = '') then    { Signs can only be added at the leftmost position }
        begin
          Sign := True;
          str_acm := str_acm + chln;
        end
        { If there's something already registered as number, a right-side Sign will mean two things }
        Else begin
          { Signs cannot be added at the right side of any number or Decimal Separator }
          If Numeric = True then   { End of the reading, in case there's already a valid series of digits }
          begin
            {Last := i-1;}              { ex.: -1.20----; -.20--- }
            If i > 1 then
            begin
              If (S[i-1] = 'E') or (S[i-1] = 'e') then
                str_acm := str_acm + chln
              Else begin
                Last := i-1;
              end;
            end;
          end
          Else begin               { A mixture of various characters without numeric logic}
            str_acm := '';         { So start over the reading }
            Sign := False;         { ex.: -.--- }
          end;
        end;
      end;
      If (chln in ['.',',']) then
      begin
        If (DeciSep = False) then        { Decimal Separators can only be added once }
        begin
          str_acm := str_acm + DecimalSeparator;
          DeciSep := True;
        end
        { If a Decimal Separator was already accounted, a second one will mean two things }
        Else begin
          If Numeric = True then   { End of the reading, in case there's already a valid series of digits }
            Last := i-1              { ex.: -1.20...; -0.20. }
          Else begin               { A mixture of various characters without numeric logic }
            str_acm := '';         { So start over the reading }
            DeciSep := False;      { ex.: -... }
          end;
        end;
      end;

      If (chln in ['0'..'9']) then
      begin
        Numeric := True;            { Numbers can be added after any other characters, be it Sign and/or Decimal Separator }
        str_acm := str_acm + chln;  { Ex.: -1; -2.1; -.1; -1. }
      end;

      If (chln = 'E') or (chln = 'e') then
      begin
        If Exponent = False then
        begin
          If Numeric = True then    { E for the power of 10 can only be added once and after a series of digits }
          begin                     { Ex.: 1.0E10; -.0E2; -4.E3 }
            str_acm := str_acm + chln;
            Exponent := True;
          end
          Else begin                { The abscense of a previous series of digits does not allow the insertion of E }
            str_acm := '';          { E cannot start a floating point number and cannot succeed a sign or }
          end;                      { decimal separator if there isn't any previous number }
        end                         { Ex.: -.E; .E; -E; E }
        Else begin
          Last := i-1;              { E cannot appear twice. A second one means the end of the reading }
        end;
      end;

      If chln = '+' then            { Plus (+) sign will only be registered after a valid exponential E character }
      begin
        If (i > 1) and (Exponent = True) then
        begin
          If (S[i-1] = 'E') or (S[i-1] = 'e') then
            str_acm := str_acm + chln
          Else begin                
            Last := i-1;            { If it's added after anything other than E, the reading ends }
          end;
        end;
        If Exponent = False then
        begin
          If (Numeric = True) then
          begin
            Last := i-1;            { If it's added after anything other than E, the reading ends }
          end
          Else begin
            str_acm := '';          { If it's added after anything other than E, and if there isn't any }
            Exponent := False;      { valid series of digits, the reading restarts }
          end;
        end;
      end;

      { If any character except the ones from the Floating Point System are added }
      If not (chln in ['0'..'9','-','+',',','.','E','e']) then
      begin
        { After an already accounted valid series of digits }
        If (str_acm <> '') then
        begin
          If (Numeric = True) then
            Last := i-1             { End of the reading. Ex.: -1.20A; -.20%; 120# }
          Else begin
            str_acm := '';
            Sign := False;  DeciSep := False;  Exponent := False;
          end;
        end;
      end;
    end;
    //ShowMessage('i = '+IntToStr(i)+#13+str_acm+'P');
  end;
  until((Last <> -1) or (i = Lstr));

  If (i = Lstr) and (Numeric = True) then
    Last := i;

  { The Loop does not filter the case when no number is inserted after E, E- or E+ }
  { So it's necessary to check and remove if E,E-,E+,e,e-,e+ are the last characters }
  If Last <> -1 then
  begin
    Lstr := length(str_acm);
    If (str_acm[Lstr] = '+') or (str_acm[Lstr] = '-') then
    begin
      SetLength(str_acm,Lstr-1);
      Last := Last - 1;
    end;

    Lstr := length(str_acm);
    If (str_acm[Lstr] = 'E') or (str_acm[Lstr] = 'e') then
    begin
      SetLength(str_acm,Lstr-1);
      Last := Last - 1;
    end;

    Result := str_acm;
  end
  Else Result := '';
end;  { ExtractFloatStr }

EDIT 2.:另一个函数使用前一个函数读取同一字符串中的一系列数字。

var
  TFloatType = real;
  TVetorN = array of TFloatType;

procedure ExtractFloatVectorStr(Str : string; var N : integer; var FloatVector : TVetorN);
var                                     { Extract floating point numbers from string reading from left to right }
  i, j, k, Lstr, Lstr1 : integer;       { Register the numbers in FloatVector as the type TVetorN }
  char1 : char;                         { Register the amount of numbers found as the integer N }
  str_acm : string;
begin
  Str := AdjustLineBreaks(Str,tlbsCRLF);
  Lstr := length(Str);
  Lstr1 := 0;
  char1 := #0;

  i := 1; j := 0; k := 0; str_acm := '';
  SetLength(FloatVector,j+1);
  repeat
  begin
    If (i <= Lstr) then
    begin
      str_acm := ExtractFloatStr(i, Str, k);
      Lstr1 := length(str_acm);
      If (Lstr1 > 0) and (str_acm <> '') then
      begin
        j := j + 1;
        SetLength(FloatVector,j+1);
        FloatVector[j] := StrToFloat(str_acm);
        i := k + 1;
      end
      Else i := i + 1;
    end;
  end;
  until(i > Lstr);
  N := j;
end;  { ExtractFloatVectorStr }