Мне нужно вывести числа из строки и поместить их в список, для этого есть некоторые правила, такие как определение того, является ли извлеченное число целым или плавающим.
Задача звучит достаточно просто, но со временем я становлюсь все более и более запутанным, и на самом деле можно сделать некоторые рекомендации.
В качестве примера возьмем следующую тестовую строку:
There are test values: P7 45.826.53.91.7, .5, 66.. 4 and 5.40.3.
При анализе строки следуют следующие правила:
-
цифры не могут быть превышены буквой.
-
Если он найдет число и не будет следовать десятичной точке, тогда число будет как целое.
-
Если он найдет число и за ним следует десятичная точка, тогда число будет float, например, 5.
-
~ Если число больше соответствует десятичной точке, тогда число по-прежнему является поплавком, например 5.40
-
~ Далее найденная десятичная точка должна затем разбить число, например 5.40.3 становится (5.40 Float) и (3 Float)
-
В случае буквы, например, после десятичной точки, например
3.H
, затем добавьте3.
в качестве поплавка в список (даже если технически это недопустимо)
Пример 1
Чтобы сделать это немного более понятным, взяв тестовую строку, указанную выше, требуемый результат должен быть следующим:
Из приведенного выше изображения светло-синий цвет показывает числа Float, бледно-красный - одиночные целые числа (но обратите внимание также, как сгруппированные поплавки разбиваются на отдельные поплавки).
- 45.826 (Float)
- 53.91 (Float)
- 7 (целое число)
- 5 (целое число)
- 66. (С плавающей точкой)
- 4 (целое число)
- 5.40 (Float)
- 3. (С плавающей точкой)
Обратите внимание, что существуют преднамеренные пробелы между 66. и 3. выше из-за способа форматирования чисел.
Пример 2:
Anoth3r Te5.t строка .4 abc 8.1Q 123.45.67.8.9
- 4 (целое число)
- 8.1 (Float)
- 123.45 (Float)
- 67.8 (Float)
- 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.