Delphi extract numbers from string

13,413

Solution 1

I think this function is what you are looking for:

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;

Solution 2

If you have Delphi XE or up, you can use regular expressions. This is completely untested, based on David Heffernan's answer:

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;

Solution 3

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 ;

Solution 4

inspired by user2029909 response

function ExtractNumberInString (sChaine: String; Start : Integer = 1): TArray<String> ;
var
  i, j: Integer ;
  TmpStr : string;
begin
  j := 0;
  for i := Start to Length( sChaine ) do
    begin
      if sChaine[ i ] in ['0'..'9'] then
        TmpStr := TmpStr + sChaine[ i ]
      else
        if TmpStr <> '' then
          begin
            SetLength(Result, Length(Result) + 1);
            Result[j] := TmpStr;
            TmpStr := '';
            Inc(j);
          end;
    end ;
end ;
Share:
13,413
colin
Author by

colin

Updated on June 07, 2022

Comments

  • colin
    colin almost 2 years

    I have a variety of strings which I need to work with, these contain both letters and numbers , I am trying to extract the numbers (which is the part I need) from the string, the strings would have a similar format to -

    the cat can count 123 567 so can the dog"

    The length and position of the numbers can vary from 12 34 123 456 1234 5678 11111 11111

    Also the number seperator can vary from a space question mark and also a dash 12-34 12.34 So the string could be EG “the cat can't count, the dog can 12-67” or “the cat can count 1234.5678 so can the dog” Is there any clever way in Delphi I can extract the numbers? Or would I have to do it by scanning the string in code.

    Any help would be appreciated

    Thanks

    colin

  • Marjan Venema
    Marjan Venema over 12 years
    +1 nice way of returning all individual numeric parts. Would hate to have to add support for returning 123.12 as a single numeric part though, especially when taking a.123, a. .123 and 123. 456 or 123 .456 etc. into consideration. :)
  • David Heffernan
    David Heffernan over 12 years
    @Marjan And there's always negative numbers, but OP does appear to regard any non-digit as a sep.
  • colin
    colin over 12 years
    @David Thanks that does the job
  • David Heffernan
    David Heffernan over 12 years
    +1 I prefer this to my version. That said if Matches.Count does not compile.
  • David Heffernan
    David Heffernan almost 5 years
    @SHINJaeGuk This happened in the 7 years that have elapsed since the answer was written. Now you use the record helper for Char and write s[i].IsDigit.
  • LU RD
    LU RD almost 3 years
    There can be multiple numbers in the string, so this answer does not answer the question.
  • LU RD
    LU RD almost 3 years
    There can be multiple numbers in the string, so this answer does not answer the question. Also, all numbers are positive integers.
  • SpeedResolve
    SpeedResolve almost 3 years
    @LU RD I can post another function I built where a series of floating point numbers is recognized and listed in a dynamic array. The function above will identify the first floating point number from the position Start on, and mark its end at Last, giving a string compatible with a subsequent StrToFloat input, if the string is different from nil.
  • LU RD
    LU RD almost 3 years
    The question is not about floating point numbers. Anything but 0..9 should be treated as space.
  • SpeedResolve
    SpeedResolve almost 3 years
    Well, you are not wrong, but I think the code I gave may help in that regard. I searched for similar subjects here in stack and didn't find this problem in Delphi. So I made it myself. It may not be the optimal place to share it, but there you go
  • Akin Okegbile
    Akin Okegbile over 2 years
    Can you add more commentary on this code?
  • Admin
    Admin over 2 years
    Please add further details to expand on your answer, such as working code or documentation citations.