【发布时间】:2017-03-13 14:59:05
【问题描述】:
我需要从字符串中提取数字并将它们放入列表中,但是有一些规则,例如识别提取的数字是整数还是浮点数。
这项任务听起来很简单,但随着时间的推移,我发现自己越来越困惑,并且真的可以通过一些指导来完成。
以下面的测试字符串为例:
There are test values: P7 45.826.53.91.7, .5, 66.. 4 and 5.40.3.
解析字符串时要遵循的规则如下:
数字前面不能有字母。
如果它找到一个数字并且不是后跟一个小数点,那么这个数字就是一个整数。
如果它找到一个数字并且 是 后跟一个小数点,则该数字是一个浮点数,例如 5。
~ 如果小数点后有更多数字,则该数字仍然是浮点数,例如 5.40
~ 进一步找到的小数点应将数字分解,例如 5.40.3 变为 (5.40 Float) 和 (3 Float)
-
如果是小数点后的字母,例如
李>3.H,则仍将3.作为浮点数添加到列表中(即使在技术上它无效)
示例 1
为了更清楚一点,在所需输出上方引用的测试字符串应如下所示:
从上图中,浅蓝色表示浮点数,浅红色表示单个整数(但请注意连接在一起的浮点数如何拆分为单独的浮点数)。
- 45.826(浮点数)
- 53.91(浮点数)
- 7(整数)
- 5(整数)
- 66。 (浮动)
- 4(整数)
- 5.40(浮点数)
- 3。 (浮动)
注意 66 之间有故意的空格。和 3。以上是由于数字的格式。
示例 2:
Anoth3r Te5.t 字符串 .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.
我的问题是如何从字符串中提取数字,将它们添加到列表中并确定数字是整数还是浮点数?
左边的淡绿色列表框(期望的输出)显示结果应该是什么,右边的淡蓝色列表框(实际输出)显示我们实际得到的结果。
请指教谢谢。
注意我在使用 XE7 时重新添加了 Delphi 标签,所以请不要删除它,尽管这个特殊问题在 Lazarus 中我最终的解决方案应该适用于 XE7 和 Lazarus。
【问题讨论】:
-
@DavidHeffernan 考虑到我花了很长时间写出我认为有效的问题(你真的不知道问题是什么?),这不是一个公平的假设,并且还展示了我的尽我所能的进步和努力。如果我希望有人为我做这一切,到目前为止,我不会为此付出太多努力,所以请不要只是假设我想要复制和粘贴答案,我只需要一些指导来帮助我,你只能从学习中发展成为一名程序员,而不是复制和粘贴,所以请不要以为我期望有人为我做这项工作。
-
我很同情,很明显你付出了很多努力。
-
@DavidHeffernan 谢谢,我真的希望我能更好、更清楚地吸收和理解这些任务,因为它们解决的时间越长,就越难。这是我的建议,希望没有人发布解决方案,同时我会抽出一些时间来解决这个问题,收集我的想法并缓解压力和困惑,然后希望回来攻击它并尝试制作更多的进步,有限状态机看起来太先进了,所以我会尝试继续我目前的方式。祝我好运:)
-
45.826.53.91.7 在哪个星球上解析出 45.826、53.91 和 7?您如何确定它不是 45、826.53 和 91.7,或 45、826、53.91 和 7?你从哪里得到这些随机噪声填充的数据?
-
@Craig 感谢您尝试为自己设置挑战以帮助您学习。但是,您可能需要先学习更重要的一课。大多数程序员都陷入了让事情变得过于复杂和困难的陷阱。你犯了这个错误。通过允许符号
.执行双重任务作为小数点和项目分隔符,您将可能是一个有趣的解析练习变成了一个不切实际的问题,您不太可能从中学到任何有用的东西。最重要的一课:不要让事情过于复杂。
标签: delphi lazarus freepascal