Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Получение из строки имени и значений параметров  [new]
Martin114
Member

Откуда:
Сообщений: 100
Стоит такая задача:
На входе задана строка, где задано название параметра и ряд его значений, разделенные пробелами (и может быть знаками табуляции) (в данном примере их 5, но может быть произвольным), на выходе - массив с именем параметра и его значениями (можно в виде строк, в числа я потом преобразую):

Пример 1:
readStr = 'Названиепарам1 -0.013 0.017 0.099 0.189 0.221*'

На выходе должно быть:
paramValues[0] = 'Названиепарам1'
paramValues[1] = '-0.013'
paramValues[2] = '0.017'
paramValues[3] = '0.099'
paramValues[4] = '0.189'
paramValues[5] = '0.221*'

Пример 2:
readStr = 'Paramname 1.691 1.764 1.829 2.007* 1.916'

На выходе должно быть:
paramValues[0] = 'Paramname'
paramValues[1] = '1.691'
paramValues[2] = '1.764'
paramValues[3] = '1.829'
paramValues[4] = '2.007*'
paramValues[5] = '1.916'

Наваял, исходя из опыта предшественников, работавшим над проектом, следующую процедуру:

procedure GetParametersShortProtocolValues(var paramValues: array of variant;
    const readStr: String);
var
    i: Integer;
    M: TMatchCollection;
    REx: TRegEx;
begin
    REx := TRegEx.Create('([a-zA-Z0-9.*-+]+)', [roIgnoreCase]);
 
    if REx.IsMatch(readStr) then
    begin
        M := REx.Matches(readStr); // получаем коллекцию совпадений
    SetLength(paramValues, M.Item[0].Groups.Count + 1); // выдает ошибку несоответствия типов
        paramValues[0] := M.Item[0].Groups[1].value;
        for i := 1 to min(M.Item[0].Groups.Count - 1, Length(paramValues) - 1) do // Вообще не заполняет массив paramValues значениями из M
            paramValues[i - 1] := M.Item[0].Groups[i].value;
    end;
end;


но получил некомпиляцию из-за ошибки несоответствия типов. В случае, когда я жестко задал SetLength(paramValues, 5), paramValues[0] присвоилось M.Item[0].Groups[1].value, но в цикле ничего не присвоилось.
28 сен 18, 19:10    [21689476]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
Гирлионайльдо
Member

Откуда:
Сообщений: 318
+
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, Variants;

function ParseArgs(const str: string): TArray<Variant>;
var
  i, valueInteger: Integer;
  Arr: TArray<string>;
  Value: string;
  valueExtended: Extended;
  delm: char;
begin
  delm := FormatSettings.DecimalSeparator;
  FormatSettings.DecimalSeparator := '.';

  Arr := str.Split([' ']);
  SetLength(Result, Length(Arr));
  for i := Low(Arr) to High(Arr) do
  begin
    Value := Arr[i];
    if TryStrToInt(Value, valueInteger) then
      Result[i] := valueInteger
    else if TryStrToFloat(Value, valueExtended, FormatSettings) then
      Result[i] := valueExtended
    else
      Result[i] := Value;
  end;
  FormatSettings.DecimalSeparator := delm;
end;

var
  v: TArray<Variant>;
  i: Integer;

begin
  try
    v := ParseArgs('Paramname 5 1.691 1.764 1.829 2.007* 1.916');
    for i := Low(v) to High(v) do
    begin
      Writeln(VarToStr(v[i]), ' : ', VarTypeAsText(VarType(v[i])));
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.


Paramname : UnicodeString
5 : Integer
1,691 : Double
1,764 : Double
1,829 : Double
2.007* : UnicodeString
1,916 : Double
28 сен 18, 21:32    [21689562]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
чччД__
Guest
Martin114,

offtopic: а если в качестве параметра понадобится передавать строку с пробелом (табуляцией)?

Посмотри, как GetParamStr() модуля System.pas сделано, там отдельные параметры могут быть квотированы двойной ковычкой, хотя, конечно, дело твое:

+
function GetNextParam(P: PChar; var Param: string): PChar;
// Как в GetParamStr() из System.pas
var
  i, Len: Integer;
  Start, S, Q: PChar;
begin
  while True do
  begin
    while (P[0] <> #0) and (P[0] <= ' ') do
      P := CharNext(P);
    if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
  end;
  Len := 0;
  Start := P;
  while P[0] > ' ' do
  begin
    if P[0] = '"' then
    begin
      P := CharNext(P);
      while (P[0] <> #0) and (P[0] <> '"') do
      begin
        Q := CharNext(P);
        Inc(Len, Q - P);
        P := Q;
      end;
      if P[0] <> #0 then
        P := CharNext(P);
    end
    else
    begin
      Q := CharNext(P);
      Inc(Len, Q - P);
      P := Q;
    end;
  end;

  SetLength(Param, Len);

  P := Start;
  S := Pointer(Param);
  i := 0;
  while P[0] > ' ' do
  begin
    if P[0] = '"' then
    begin
      P := CharNext(P);
      while (P[0] <> #0) and (P[0] <> '"') do
      begin
        Q := CharNext(P);
        while P < Q do
        begin
          S[i] := P^;
          Inc(P);
          Inc(i);
        end;
      end;
      if P[0] <> #0 then P := CharNext(P);
    end
    else
    begin
      Q := CharNext(P);
      while P < Q do
      begin
        S[i] := P^;
        Inc(P);
        Inc(i);
      end;
    end;
  end;

  Result := P;
end;

function GetParamByIndex(apCommandLine: PChar; index: Integer): string;
begin
  while True do
  begin
    apCommandLine := GetNextParam(apCommandLine, Result);
    if (Index = 0) or (Result = '') then Break;
    Dec(Index);
  end;
end;
28 сен 18, 22:00    [21689582]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
defecator
Member

Откуда:
Сообщений: 38962
Martin114
Стоит такая задача:
На входе задана строка, где задано название параметра и ряд его значений, разделенные пробелами (и может быть знаками табуляции) (в данном примере их 5, но может быть произвольным), на выходе - массив с именем параметра и его значениями (можно в виде строк, в числа я потом преобразую):

Пример 1:
readStr = 'Названиепарам1 -0.013 0.017 0.099 0.189 0.221*'

На выходе должно быть:
paramValues[0] = 'Названиепарам1'
paramValues[1] = '-0.013'
paramValues[2] = '0.017'
paramValues[3] = '0.099'
paramValues[4] = '0.189'
paramValues[5] = '0.221*'

Пример 2:
readStr = 'Paramname 1.691 1.764 1.829 2.007* 1.916'

На выходе должно быть:
paramValues[0] = 'Paramname'
paramValues[1] = '1.691'
paramValues[2] = '1.764'
paramValues[3] = '1.829'
paramValues[4] = '2.007*'
paramValues[5] = '1.916'


как вариант, самый простой, использовать TStringList
var
  SL : TStringList ;
begin
  SL := TSTringList.Create ;
  SL.Delimiter := ' ' ;
  S:.DelimitedText := 'Paramname 1.691 1.764 1.829 2.007* 1.916' ;
.....
end;


фсё
28 сен 18, 22:07    [21689587]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
Котовасия
Member

Откуда:
Сообщений: 1187
defecator,

это да. Но ТС хочет иного.
28 сен 18, 22:13    [21689591]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
defecator
Member

Откуда:
Сообщений: 38962
Котовасия
defecator,

это да. Но ТС хочет иного.

не увидел иного
28 сен 18, 22:20    [21689593]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
Гирлионайльдо
Member

Откуда:
Сообщений: 318
  Arr := str.Split([' ', #9]);



Гирлионайльдо
+
[spoiler ]
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, Variants;

function ParseArgs(const str: string): TArray<Variant>;
var
  i, valueInteger: Integer;
  Arr: TArray<string>;
  Value: string;
  valueExtended: Extended;
  delm: char;
begin
  delm := FormatSettings.DecimalSeparator;
  FormatSettings.DecimalSeparator := '.';

  Arr := str.Split([' ']);
  SetLength(Result, Length(Arr));
  for i := Low(Arr) to High(Arr) do
  begin
    Value := Arr[i];
    if TryStrToInt(Value, valueInteger) then
      Result[i] := valueInteger
    else if TryStrToFloat(Value, valueExtended, FormatSettings) then
      Result[i] := valueExtended
    else
      Result[i] := Value;
  end;
  FormatSettings.DecimalSeparator := delm;
end;

var
  v: TArray<Variant>;
  i: Integer;

begin
  try
    v := ParseArgs('Paramname 5 1.691 1.764 1.829 2.007* 1.916');
    for i := Low(v) to High(v) do
    begin
      Writeln(VarToStr(v[i]), ' : ', VarTypeAsText(VarType(v[i])));
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.


Paramname : UnicodeString
5 : Integer
1,691 : Double
1,764 : Double
1,829 : Double
2.007* : UnicodeString
1,916 : Double
[/spoiler]
28 сен 18, 22:30    [21689597]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
Гирлионайльдо
Member

Откуда:
Сообщений: 318
Ну или так
Arr := str.Split(['  ', ' ']);
28 сен 18, 22:33    [21689602]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
Martin114
Member

Откуда:
Сообщений: 100
defecator,

Мне уже посоветовали этот вариант. Я сделал так:
function StrCondition(aStr: String): String;
begin
    result := StringReplace(aStr, #32, ';', [rfReplaceAll]); //Заменяем пробелы на ;
    result := StringReplace(result, #9, ';', [rfReplaceAll]); //Заменяем табуляторы на ;
end;
 
procedure GetParameters(const readStr: String);
var
    L: TStringList;
    DelimStr: string;
    i: Integer;
    S: array [0 .. 5] of string;
begin
   L := TStringList.Create; //Создаем СтрингЛист
   L.Delimiter := ';'; //Задаем разделитель
   DelimStr := StrCondition(readStr); //Разбиваем строку на части по разделителю
   L.DelimitedText := DelimStr;
 
   S[0] := L.Strings[0];
   S[1] := L.Strings[1];
   S[2] := L.Strings[2];
   S[3] := L.Strings[3];
 
   L.Free;
end;


Задаем readStr = 'Cmax -0.033 0.021 0.084 0.189 0.204*'. В результате получилось:
DelimStr = 'Cmax;;;;;;-0.033;;;;0.021;;;;0.084;;;;0.189;;;;0.204*'
S[0] = 'Cmax'; S[1] - S[3] - пустые строки. Почему так?
1 окт 18, 17:20    [21691618]     Ответить | Цитировать Сообщить модератору
 Re: Получение из строки имени и значений параметров  [new]
Martin114
Member

Откуда:
Сообщений: 100
Проблема решена:

var L: TStringList;
begin
  L := TStringList.Create;
  L.DelimitedText := StringReplace(readStr, #9, #32, [rfReplaceAll]);
end;
2 окт 18, 14:53    [21692743]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить