Перечисление строки

У меня есть статус, который хранится в виде строки заданной длины либо в файле, либо в базе данных.

Я ищу, чтобы перечислить возможный статус'

У меня есть следующий тип для определения возможного статуса'

Type TStatus = (fsNormal = Ord('N'),fsEditedOnScreen = Ord('O'),
                fsMissing = Ord('M'),fsEstimated = Ord('E'),fsSuspect = Ord('s'),
                fsSuspectFromOnScreen = Ord('o'),fsSuspectMissing = Ord('m'),
                fsSuspectEstimated = Ord('e'));

Во-первых, это действительно хорошая идея? или у меня должен быть отдельный массив const для хранения преобразований char? Это означало бы более одного места для обновления.

Теперь преобразуйте строку в массив состояния. У меня есть следующее, но как я могу проверить, действителен ли символ, не перебирая перечисление?

Function StrToStatus(Value : String):TStatusArray;
var
    i: Integer;
begin
    if Trim(Value) = '' then
    begin
        SetLength(Result,0);
        Exit;
    end;
    SetLength(Result,Length(Value));
    for i := 1 to Length(Value) do
    begin
        Result[i] := TStatus(Value[i]); // I don't think this line is safe.
    end;
end;

После некоторого тестирования подозрительная строка безопасна (она не падает!), но просто добавляет (за пределы) значения, которые затем необходимо отфильтровать.

Function StrToStatus(Value : String):TStatusArray;
var
    i: Integer;
begin
    if Trim(Value) = '' then
    begin
        SetLength(Result,0);
        Exit;
    end;
    SetLength(Result,Length(Value));
    for i := 1 to Length(Value) do
    begin
        Result[i-1] := TStatus(Value[i]);
    end;
    for i := 0 to Length(Result) - 1 do
    begin
        case Result[i] of
            fsNormal: ;
            fsEditedOnScreen: ;
            fsMissing: ;
            fsEstimated: ;
            fsSuspect: ;
            fsSuspectFromOnScreen: ;
            fsSuspectMissing: ;
            fsSuspectEstimated: ;
            else
                Result [i] := fsNormal;
        end;
    end;
end;

Это позволяет всем состояниям и их относительным значениям Char быть в одном месте и предотвращает зацикливание каждого состояния для каждого символа в строке. (Так что в моей голове, по крайней мере, должно быть немного быстрее)

AFAIK, это должно подойти для повторного преобразования.

Function StatusToStr(Value : TStatusArray):String;
var
  i: Integer;
begin
    for i := 0 to Length(Value) - 1 do
        Result := Result + Chr(Ord(Value[i]))
end;

Я использую Делфи 2007


person James Barrass    schedule 18.03.2010    source источник


Ответы (2)


Если я правильно вас понимаю, я бы заменил массив набором и использовал перечисление без явных значений, например:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TStatus = (fsNormal, fsEditedOnScreen, fsMissing, fsEstimated, fsSuspect,
    fsSuspectFromOnScreen, fsSuspectMissing, fsSuspectEstimated);
  TStatusSet = set of TStatus;

const
  cStatusChars: array[TStatus] of Char = ('N', 'O', 'M', 'E', 's', 'o', 'm', 'e');

function CharToStatus(AChar: Char; out AStatus: TStatus): Boolean;
var
  st: TStatus;
begin
  for st := Low(TStatus) to High(TStatus) do
    if cStatusChars[st] = AChar then
    begin
      AStatus := st;
      Result := True;
      Exit;
    end;
  Result := False;
end;

function StrToStatus(const Value: string): TStatusSet;
var
  i: Integer;
  st: TStatus;
begin
  Result := [];
  for i := 1 to Length(Value) do
    if CharToStatus(Value[i], st) then
      Include(Result, st);
end;

function StatusToStr(const Value: TStatusSet): string;
var
  st: TStatus;
begin
  for st in Value do
    Result := Result + cStatusChars[st];
end;

var
  StatusSet: TStatusSet;
begin
  StatusSet := StrToStatus('EmO');
  Writeln(StatusToStr(StatusSet));
  Readln;
end.
person Uli Gerhardt    schedule 18.03.2010
comment
Мне нужно, чтобы результат был массивом, а не набором (строка представляет собой различный статус нескольких значений, каждое значение может иметь только один статус). Кроме того, должны ли у меня быть проблемы с производительностью с дополнительным циклом? - person James Barrass; 19.03.2010
comment
Под дополнительным циклом вы подразумеваете тот, что в CharToStatus? Вы можете заменить его, создав массив поиска array[Char] of TStatus перед тем, как использовать StrToStatus в первый раз. Я понятия не имею, ускорит ли это процесс. - person Uli Gerhardt; 19.03.2010

Во-первых, мне интересно, почему вы сохраняете его как строку, а не как целое число.

То, как вы это сделали, единственный способ сделать это правильно - это иметь условие Case...

function CharToStatus(AChar : Char):TStatus;
begin
  case AChar of
    'N' : Result := fsNormal;
    'O' : Result := fsEditedOnScreen;
    'M' : Result := fsMissing;
    'E' : Result := fsEstimated;
    's' : Result := fsSuspect;
    'o' : Result := fsSuspectFromOnScreen;
    'm' : Result := fsSuspectMissing;
    'e' : Result := fsSuspectEstimated;
  else
    //Manage error;
  end;
end;

function StatusToChar(AStatus : TStatus) : char;
begin
  Result := Char(AStatus);
end;

Выражение x in [Low(TStatus)]..High(Tstatus)] в этой ситуации работать не будет. Причина этого в том, что Low(TSatus) = 'E', а High(TSStatus) = 's'. Все, что находится между ними, будет считаться действительным. (т.е. «Z» находится в [Низкий (TSStatus)].. Высокий (Tstatus)])

Выражение x in [Low(TStatus)]..High(Tstatus)] работает только с типом, в объявлении которого нет «дыры». (Например, без явных значений, где первый элемент равен 0, 2-й - 1, 3-й - 2... и т.д.)

//РЕДАКТИРОВАТЬ

Хорошо... подумав о проблеме немного дальше, я не понимаю, почему вам не нравится подход с константным массивом... Что-то вроде этого было бы намного лучше.

type
  TStatus = (fsNormal, fsEditedOnScreen,
                fsMissing,fsEstimated,fsSuspect,
                fsSuspectFromOnScreen,fsSuspectMissing ,
                fsSuspectEstimated);
const
  StatusValue : Array[TStatus] of Char = ('N','O','M','E','s','o','m','e');

function StatusValueToTStatus(C : Char) : TStatus;
var I : Integer;
begin
  for I := Low(StatusValue) to High(StatusValue)  do
  begin
    if StatusValue = C then
    begin
      Result := TStatus(I);
      EXIT;
    end;
  end;
  //Not found, Manage errors
end;
person Ken Bourassa    schedule 18.03.2010
comment
Он сохраняется как строка как часть устаревшей системы. Причина, по которой я не выбрал подход const, заключалась просто в том, что я вижу, как другие разработчики нарушают его, проявляя некоторую небрежность при добавлении нового статуса. - person James Barrass; 19.03.2010
comment
Если они не корректируют длину массива после добавления нового значения перечисления, код не скомпилируется. - person Uli Gerhardt; 19.03.2010