- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要从字符串中提取数字并将它们放入列表中,但是这有一些规则,例如识别提取的数字是整数还是 float 。
这个任务听起来很简单,但随着时间的推移,我发现自己越来越困惑,并且确实需要一些指导。
<小时/>以下面的测试字符串为例:
There are test values: P7 45.826.53.91.7, .5, 66.. 4 and 5.40.3.
解析字符串时遵循的规则如下:
数字前面不能有字母。
如果找到一个数字并且后面没有小数点,则该数字为整数。
如果找到一个数字并且后跟一个小数点,则该数字是 float ,例如5。
~ 如果小数点后面有更多数字,则该数字仍然是 float ,例如 5.40
~ 进一步找到的小数点应将数字分解,例如 5.40.3 变为 (5.40 Float) 和 (3 Float)
如果小数点后面有字母,例如 3.H
,则仍然将 3.
作为 Float 添加到列表中(甚至如果从技术上讲它是无效的)
示例 1
为了使这一点更清晰,将所需输出上面引用的测试字符串应如下所示:
从上图中,浅蓝色表示 float ,淡红色表示单个整数(但还要注意连接在一起的 float 如何拆分为单独的 float )。
- 45.826 (Float)
- 53.91 (Float)
- 7 (Integer)
- 5 (Integer)
- 66 . (Float)
- 4 (Integer)
- 5.40 (Float)
- 3 . (Float)
请注意,66 之间有意留有空格。和 3 .由于数字的格式化方式而导致上述结果。
示例 2:
Anoth3r Te5.t string .4 abc 8.1Q 123.45.67.8.9
<小时/>
- 4 (Integer)
- 8.1 (Float)
- 123.45 (Float)
- 67.8 (Float)
- 9 (Integer)
为了提供更好的想法,我在测试时创建了一个新项目,如下所示:
<小时/>现在开始执行实际任务。我想也许我可以从字符串中读取每个字符,并根据上面的规则识别哪些是有效数字,然后将它们拉入列表中。
就我的能力而言,这是我能做到的最好的:
代码如下:
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.
<小时/>
我的问题是如何从字符串中提取数字,将它们添加到列表中并确定数字是整数还是 float ?
左侧淡绿色列表框(所需输出)显示结果应该是什么,右侧淡蓝色列表框(实际输出)显示我们实际得到的结果。
请指教,谢谢。
注意,我在使用 XE7 时重新添加了 Delphi 标签,因此请不要删除它,尽管这个特定问题出现在 Lazarus 中,但我的最终解决方案应该适用于 XE7 和 Lazarus。
最佳答案
你的规则相当复杂,所以你可以尝试构建有限状态机(FSM,DFA - Deterministic finite automaton)。
每个字符都会导致状态之间的转换。
例如,当您处于“整数启动”状态并遇到空格字符时,您将产生整数值,并且 FSM 进入“任何想要的”状态。
如果处于“整数开始”状态并遇到“.”,FSM 就会进入“浮点或整数列表开始”状态,依此类推。
关于delphi - 有没有一种简单的方法可以按照一定的规则从字符串中提取数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40343674/
我正在尝试开发右边框/Angular 具有特定 Angular (30°) 的表格。我见过一些类似的解决方案,但它们都无法在一定程度上发挥作用。如果我想从 30° 改变到 20°,我不想花太多力气。
我是一名优秀的程序员,十分优秀!