我需要从一个字符串中提取数字并将它们放入一个列表中,但是对此有一些规则,例如标识提取的数字是整数还是浮点数。是否有一种简单的方法从一个字符串中提取数字,遵循特定的规则?
这个任务听起来很简单,但随着时间的推移,我发现自己越来越困惑,并且可以真正做到一些指导。
采取以下测试字符串作为一个例子:
There are test values: P7 45.826.53.91.7, .5, 66.. 4 and 5.40.3.
的规则解析所述字符串时遵循如下:
号码不能用字母来preceeded。
如果它找到一个数字并且是而不是后跟一个小数点,那么该数字就是一个整数。
如果它发现了一些和是后跟一个小数点然后数为浮点数,例如5.
〜如果更多的数字跟随在小数点然后数目仍然是一个浮动,例如5.40
〜甲进一步发现小数点应该然后分手的数量,例如5.40.3变为(5.40浮点型)和(3浮动)
在例如一个字母的以下小数点的情况下,例如
3.H
然后仍添加3.
作为浮动到列表中(即使在技术上它是无效的)
实施例1
为了使这一点更为清晰,同时所需的输出上面引述的测试字符串应该如下:
从上图中,浅蓝色表示浮点数,淡红色表示单个整数(但也要注意浮点如何连接在一起被拆分为单独的浮点数)。
- 45.826(浮点型)
- 53.91(浮点型)
- 7(整数)
- 5(整数)
- 66。 (浮点型)
- 4(整数)
- 5.40(浮点型)
- 3。(浮点型)
注有66之间故意空格。和3。以上是由于数字格式化的方式。
实施例2:
Anoth3r Te5.t串0.4 ABC 8.1Q 123.45.67.8.9
- 4(整数)
- 8.1(浮动)
- 123.45(浮动)
- 67.8(浮点)
- 9(整数)
为了给出一个更好的主意,我创建了一个新的项目,同时测试其看起来是这样的:
现在到实际的任务。我想也许我可以从字符串中读取每个字符,并根据上述规则确定什么是有效数字,然后将它们拉入列表中。
以我的能力,这是最好的,我可以管理:
的代码如下:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnParseString: TButton;
edtTestString: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
lstDesiredOutput: TListBox;
lstActualOutput: TListBox;
procedure btnParseStringClick(Sender: TObject);
private
FDone: Boolean;
FIdx: Integer;
procedure ParseString(const Str: string; var OutValue, OutKind: string);
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.ParseString(const Str: string; var OutValue, OutKind: string);
var
CH1, CH2: Char;
begin
Inc(FIdx);
CH1 := Str[FIdx];
case CH1 of
'0'..'9': // Found a number
begin
CH2 := Str[FIdx - 1];
if not (CH2 in ['A'..'Z']) then
begin
OutKind := 'Integer';
// Try to determine float...
//while (CH1 in ['0'..'9', '.']) do
//begin
// case Str[FIdx] of
// '.':
// begin
// CH2 := Str[FIdx + 1];
// if not (CH2 in ['0'..'9']) then
// begin
// OutKind := 'Float';
// //Inc(FIdx);
// end;
// end;
// end;
//end;
end;
OutValue := Str[FIdx];
end;
end;
FDone := FIdx = Length(Str);
end;
procedure TForm1.btnParseStringClick(Sender: TObject);
var
S, SKind: string;
begin
lstActualOutput.Items.Clear;
FDone := False;
FIdx := 0;
repeat
ParseString(edtTestString.Text, S, SKind);
if (S <> '') and (SKind <> '') then
begin
lstActualOutput.Items.Add(S + ' (' + SKind + ')');
end;
until
FDone = True;
end;
end.
它显然没有得到期望的输出(失败码已被评论),我的做法可能是错误的,但我觉得我只需要在这里和那里做一些改变,以获得一个可行的解决方案。
在这一点上,我发现自己很迷茫,尽管认为答案非常接近,但相当迷茫,任务变得越来越令人愤怒,我非常感谢一些帮助。
编辑1
在这里,我得到了,因为不再重复号码靠近一点点,但结果仍然是明显的错误。
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnParseString: TButton;
edtTestString: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
lstDesiredOutput: TListBox;
lstActualOutput: TListBox;
procedure btnParseStringClick(Sender: TObject);
private
FDone: Boolean;
FIdx: Integer;
procedure ParseString(const Str: string; var OutValue, OutKind: string);
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
// Prepare to pull hair out!
procedure TForm1.ParseString(const Str: string; var OutValue, OutKind: string);
var
CH1, CH2: Char;
begin
Inc(FIdx);
CH1 := Str[FIdx];
case CH1 of
'0'..'9': // Found the start of a new number
begin
CH1 := Str[FIdx];
// make sure previous character is not a letter
CH2 := Str[FIdx - 1];
if not (CH2 in ['A'..'Z']) then
begin
OutKind := 'Integer';
// Try to determine float...
//while (CH1 in ['0'..'9', '.']) do
//begin
// OutKind := 'Float';
// case Str[FIdx] of
// '.':
// begin
// CH2 := Str[FIdx + 1];
// if not (CH2 in ['0'..'9']) then
// begin
// OutKind := 'Float';
// Break;
// end;
// end;
// end;
// Inc(FIdx);
// CH1 := Str[FIdx];
//end;
end;
OutValue := Str[FIdx];
end;
end;
OutValue := Str[FIdx];
FDone := Str[FIdx] = #0;
end;
procedure TForm1.btnParseStringClick(Sender: TObject);
var
S, SKind: string;
begin
lstActualOutput.Items.Clear;
FDone := False;
FIdx := 0;
repeat
ParseString(edtTestString.Text, S, SKind);
if (S <> '') and (SKind <> '') then
begin
lstActualOutput.Items.Add(S + ' (' + SKind + ')');
end;
until
FDone = True;
end;
end.
我的问题是我怎么能提取数字从一个字符串,将它们添加到列表,并决定如果数字是整数或浮点数?
左边淡绿色的列表框(需要的输出)显示结果应该是什么,右边淡蓝色的列表框(实际输出)显示了我们实际得到的结果。
请指教谢谢。
注意我重新添加了Delphi标签,因为我使用XE7,所以请不要删除它,尽管这个特殊问题在Lazarus中,我最终的解决方案应该适用于XE7和Lazarus。
看看'System.Masks.MatchesMask'函数。我没有尝试,但这可能可以帮助你。 –
@DavidHeffernan考虑到我写出我认为是一个有效问题的时间(你真的不知道问题是什么?),这不是一个公平的假设,并且也展示了我的进步和努力,以最好的我的能力。如果我想要一个人为我做这一切,那么我不会付出太多的努力,所以请不要假设我想要一个复制和粘贴的答案,我只需要一些指导来帮助我在路上,你只能从程序员的角度来学习而不是复制和粘贴,所以请不要假设我期望有人为我完成这项工作。 – Craig
那么你的问题是什么。非常具体。 –