delphi – 有一个简单的方式从字符串中提取数字按照某些规则?

我需要从一个字符串中拉出数字并把它们放入一个列表中,但是有一些规则,例如识别提取的数字是整数还是浮点数。

这个任务听起来很简单,但随着时间的推移,我越来越感到困惑,可能真的有一些指导。

以下列测试字符串为例:

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 (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,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,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);
    if (S <> '') and (SKind <> '') then
    begin
      lstActualOutput.Items.Add(S + ' (' + SKind + ')');
    end;
  until
    FDone = True;
end;

end.

我的问题是如何从字符串中提取数字,将它们添加到列表中,并确定数字是整数还是浮点数?

左边的绿色绿色列表框(所需输出)显示结果应该是什么,右侧的淡蓝色列表框(实际输出)显示了我们实际获得的结果。

请指教谢谢

注意我重新添加了Delphi标签,因为我使用XE7,所以请不要删除它,虽然这个特别的问题是在拉撒路我的最终解决方案应该适用于XE7和拉撒路。

解决方法

您的规则相当复杂,因此您可以尝试构建有限状态机(FSM,DFA – Deterministic finite automaton)。

每个字符都会导致状态之间的转换。

例如,当你处于状态“integer start”并且满足空格时,你会得到整数值,而FSM进入“任何需要的”状态。

如果处于状态“整数开始”并且满足’。’,则FSM进入状态“float或整数列表开始”等等。

相关文章

 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都...
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上...
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c+&#x...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和ED...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的...