我有各种各样的字符串,我需要使用它们,它们包含字母和数字,我试图从字符串中提取数字(这是我需要的部分),字符串将具有类似的格式 -
这只猫可以算上123 567,所以狗可以“数字的长度和位置可能不同 12 34 123 456 1234 5678 11111 11111
此号码分隔符也可能与空格问号和短划线不同 12-34 12.34 所以字符串可能是EG“猫不能算,狗可以12-67”或“猫可以算1234.5678这样可以狗” 在Delphi中有什么聪明的方法可以提取数字吗?或者我必须通过扫描代码中的字符串来完成它。
任何帮助将不胜感激
由于
科林
答案 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 }