Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.08.27;
Скачать: CL | DM;

Вниз

Case of для строк   Найти похожие ветки 

 
ford ©   (2010-03-31 17:24) [0]

Здравствуйте!
в программу передается параметр от которого зависит какая из процедур должна быть выполнена. Значений параметра около десятка.

я сделал следующим образом

if ParamStr(1)="create" then createnewfile(paramstr(2))
 else if ParamStr(1)="send" then sendfile(paramstr(2))
       else ....


подскажите, можно ли реализовать это как Case of
т.е. примерно так:


Case ParamStr(1) of
"create" : createnewfile(paramstr(2));
"send"   : sendfile(paramstr(2));
...
else
...
end;


понятно что Case не работает для строк
но все же :)


 
12 ©   (2010-03-31 17:30) [1]

Завести массив соответствий типа
"create" - 1
"send"- 2

функцию преобразования

case Func(ParamStr(1)) of
1:
2:
else
end;


 
Демо ©   (2010-03-31 17:33) [2]

Посмотри здесь.
Мало-ли, может понравится приём.

http://forum.sources.ru/index.php?showtopic=299079


 
Игорь Шевченко ©   (2010-03-31 17:37) [3]

Демо ©   (31.03.10 17:33) [2]

Че, такой секретный форум ? "У вас нет прав для просмотра этой темы"


 
Демо ©   (2010-03-31 17:38) [4]


> Игорь Шевченко ©   (31.03.10 17:37) [3]
> Демо ©   (31.03.10 17:33) [2] Че, такой секретный форум
> ? "У вас нет прав для просмотра этой темы"


Странно. Там заготовки для FAQ лежат.


 
Демо ©   (2010-03-31 17:39) [5]

Вот. Просто копирую сюда.

Case для строк

Часто бывает, что нужно проверить строку на совпадение с рядом заранее заданных значений. Case для этого подходит идеально, но, к сожалению, он работает только с перечислимыми типами. Приходится использовать ряд сравнений, и если набор сравниваемых значений превышает 5 элементов, код превращается в маловразумительную городушку из if-then-else.

Можно, конечно, загнать варианты в TStringList - но придётся заботиться о создании/удалении. Статическая константа-массив тоже не всегда выход. Задачу можно решить с помощью безымянной константы-массива.

...
 case IndexStr(s, ["variant 1", "variant 2", "variant 3", "variant 4", "variant 5", "variant 6", "variant 7"] ) of
   0:   idx := 0; // or do something
   1:   idx := 1; // or do something
   2:   idx := 2; // --- || ---
   3:   idx := 3;
   4:   idx := 4;
   5:   idx := 5;
   6:   idx := 6;
   7:   idx := 7;
   else idx := -1; // not found
 end;
...



Также можно составлять массив и из переменных:
 case IndexStr(s, [Form1.Caption, Button1.Caption, Edit1.Text] ) of

Проведя ряд тестов, я выяснил, что IndexStr (она же AnsiIndexStr) очень неэффективна: она вызывает WinAPI функцию CompareString, да еще и с двумя вложенными вызовами. Но если использовать свою функцию, которая будет просто сравнивать строки

function NewIndexStr(const AText: string; const AValues: array of string): Integer;
var
 I: Integer;
begin
 Result := -1;
 for I := Low(AValues) to High(AValues) do
   if AText = AValues[I] then
   begin
     Result := I;
     Break;
   end;
end;


то скорость по сравнению с многоступенчатыми if-then-else будет идентична и даже немного выше.

Более того, этот метод можно легко приспособить для любых типов: указатели, вещественные числа, записи - достаточно лишь модифицировать объявление у функции поиска. Также, подозреваю, можно использовать Variant типы и функцию VarSameValue, но мне пока не удалось понять, как перейти от TVarData к Variant.


 
evvcom ©   (2010-03-31 17:55) [6]


> пока не удалось понять, как перейти от TVarData к Variant

   with TVarData(VariantValue) do
     case VType of
       varEmpty,
       varNull:     Result := 0;
       varSmallInt: Result := VSmallInt;
       varInteger:  Result := VInteger;
       varSingle:   Result := Round(VSingle);
       varDouble:   Result := Round(VDouble);
       varBoolean:  Result := Integer(VBoolean);
       varShortInt: Result := VShortInt;
       varByte:     Result := VByte;
       varWord:     Result := VWord;
       varLongWord: Result := VLongWord;
       varInt64:    Result := VInt64;
       varString:   Result := StrToInt(PChar(VString));
       else VarCastError;
     end;

это так... кусок рабочего кода, смысл думаю понятен


 
Leonid Troyanovsky ©   (2010-03-31 18:46) [7]


> Демо ©   (31.03.10 17:39) [5]

> тоже не всегда выход. Задачу можно решить с помощью безымянной
> константы-массива.

By Vladimir Titov:

http://rsdn.ru/forum/delphi/476748.1.aspx

--
Regards, LVT.


 
Игорь Шевченко ©   (2010-03-31 18:53) [8]

Демо ©   (31.03.10 17:39) [5]

я понимаю, каждому хочется показать, какие возможности Delphi он выучил, но за подобный код я бы драл розгами на конюшне, так как неочевиден он. Высчитывать нужную позицию...


 
Leonid Troyanovsky ©   (2010-03-31 18:53) [9]


> Демо ©   (31.03.10 17:39) [5]

> то скорость по сравнению с многоступенчатыми if-then-else
> будет идентична и даже немного выше.

Не будет.
Может сравниваться лишь с TStringList подходящего размера,
но, не уверен про Sorted,

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2010-03-31 18:55) [10]


> Игорь Шевченко ©   (31.03.10 18:53) [8]

А я б и за [6] тоже проголосовал.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2010-03-31 19:00) [11]


> Игорь Шевченко ©   (31.03.10 17:37) [3]

Это секретная тема.

--
Regards, LVT.


 
Демо ©   (2010-03-31 19:03) [12]

Да не мой это код.
Так - мельком пробежался.

Пусть автор сам разбирается с тем, что там неправильно.

Главное - принцип понять.


 
Leonid Troyanovsky ©   (2010-03-31 19:05) [13]


> Демо ©   (31.03.10 19:03) [12]

> Так - мельком пробежался.

Т.е., ты это который мимо проходил?

Рекомендовал, значит отдувайся.

--
Regards, LVT.


 
_Юрий   (2010-03-31 19:13) [14]


> но за подобный код я бы драл розгами на конюшне


Мы используем почти в точности такой паттерн уже пару лет, в хвост и в гриву.
(у нас еще передается параметром признак CaseSencitive).
Сказать, сколько было за это время с ним проблем?

Ровно 0 случаев.


 
Leonid Troyanovsky ©   (2010-03-31 19:16) [15]


> Юрий   (31.03.10 19:13) [14]

> Мы используем почти в точности такой паттерн уже пару лет,
>  в хвост и в гриву.

А что за нужда к этому подтолкнула?

--
Regards, LVT.


 
_Юрий   (2010-03-31 19:23) [16]


> Leonid Troyanovsky ©   (31.03.10 19:16) [15]
>
>


Собственно, удобство кодирования.
Применимо, разумеется, только для случаев, когда элементов в массиве немного, и когда их индексы видны "невооруженным глазом".
Скорость не замеряли, в нашем случае она неважна - функция вызывается однократно


 
Игорь Шевченко ©   (2010-03-31 20:35) [17]

_Юрий   (31.03.10 19:23) [16]

Ну не лень вам два места синхронизировать


 
Leonid Troyanovsky ©   (2010-03-31 20:50) [18]


> _Юрий   (31.03.10 19:23) [16]

> Собственно, удобство .

Удобство кодирования неочевидно, особенно для сase.
Бо, заранее неизвестно сколько строк в будущем в оный поступит.
Т.к., строки, очевидно, поступают извне, то необходим механизм,
максимально упрощающий изменения кода при изменении списка управляющих слов. IMHO, case для оного механизма - последний выбор.

--
Regards, LVT.


 
_Юрий   (2010-03-31 21:22) [19]


> Игорь Шевченко ©   (31.03.10 20:35) [17]


> Leonid Troyanovsky ©   (31.03.10 20:50) [18]


Нет, извне строки не поступают. Речь идет именно о случае, когда массив объявляется тут же

case IndexStr(s, ["variant 1", "variant 2", "variant 3"] ) of
  0:   DoVariant1();
  1:   DoVariant2();
  2:   DoVariant3();
  else // not found
end;

Если массив приходит сюда параметром, и мы оказываемся вынуждены синхронизировать два места,  то тогда совершенно справедливо [8]


 
sniknik ©   (2010-03-31 21:29) [20]

> А я б и за [6] тоже проголосовал.
по моему это часть VCL... видел в генофонде. или очень похожее.


 
Leonid Troyanovsky ©   (2010-03-31 21:54) [21]


> sniknik ©   (31.03.10 21:29) [20]

> по моему это часть VCL... видел в генофонде. или очень похожее.

Возможно, что это напоминает Object Pascal Language Guide:

Variant open array parameters.
function MakeStr(const Args: array of const): string;

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2010-03-31 22:10) [22]


> _Юрий   (31.03.10 21:22) [19]

> Нет, извне строки не поступают.

Если импорт строк исключен, то мне немного сложно представить
необходимость их пользования в данном случае.

Т.е., члены вашей команды обмениваются оными строками
и используют их в коде как уникальные идентификаторы?

--
Regards, LVT.


 
Германн ©   (2010-04-01 01:07) [23]


> Т.е., члены вашей команды обмениваются оными строками
> и используют их в коде как уникальные идентификаторы?
>

И такое бывает. :)
Лично встречал.


 
Leonid Troyanovsky ©   (2010-04-01 01:31) [24]


> Германн ©   (01.04.10 01:07) [23]

> > Т.е., члены вашей команды обмениваются оными строками
> > и используют их в коде как уникальные идентификаторы?

> И такое бывает. :)
> Лично встречал.

Даже если так, то никто не мешает им обмениваться, скажем,
целочисленными, вполне пригодными к case.

Могу даже предположить, например, как реализовать это
с помощью текстового файла.

--
Regards, LVT.


 
Германн ©   (2010-04-01 01:46) [25]


> Leonid Troyanovsky ©   (01.04.10 01:31) [24]
>
>
> > Германн ©   (01.04.10 01:07) [23]
>
> > > Т.е., члены вашей команды обмениваются оными строками
> > > и используют их в коде как уникальные идентификаторы?
>
>
> > И такое бывает. :)
> > Лично встречал.
>
> Даже если так, то никто не мешает им обмениваться, скажем,
>
> целочисленными, вполне пригодными к case.

Ты не в теме, Леонид.
У меня была, да и сейчас существует и продаётся (вот только вчера-позавчера обновил инсталляторы) ПО, в котором две программы обмениваются информацией по TCP/IP. Работают нормально без всяких проблем. Но возник как-то новый "руководитель работ", который захотел этот обмен "пристроить" к запросу некоего потенциального заказчика. А как проверять новые возможности? Смотреть на двоичные данные? Это же геморрой для него! Таки было выставлено требование, чтобы обмен шел в текстовом виде. Который можно прочитать в Блокноте :)


 
Leonid Troyanovsky ©   (2010-04-01 08:15) [26]


> Германн ©   (01.04.10 01:46) [25]

> У меня была, да и сейчас существует и продаётся (вот только
> вчера-позавчера обновил инсталляторы) ПО, в котором две
> программы обмениваются информацией по TCP/IP.

Если они обмениваются, то у обеих есть импорт (строк).
А тут извне строки не поступают.

Кто там у нас  не в теме? :)

--
Regards, LVT.


 
ford ©   (2010-04-01 09:26) [27]

спасибо за предложенные варианты :)


 
_Юрий   (2010-04-01 19:54) [28]


> Leonid Troyanovsky ©   (31.03.10 22:10) [22]



> Если импорт строк исключен, то мне немного сложно представить
> необходимость их пользования в данном случае.
>


Приведу пример:
грузимся их XML
Начинаем обработку очередного узла
var  Node: IXMLNode;

Требуется создать дочерний объект нужного класса в зависимости от имени узла, и вызвать его загрузку.

Как решать задачу...
Можно сделать регистрацию классов, и искать нужный класс в цикле, сравнивая имя Node с результатом какого-нибудь классового виртуального метода общего предка:

for I:=0 to ClassList.Count -1 do
 if TMyClass(ClassList[I]).GetXMLNodeName = Node.NodeName then
 begin
   Result:=TMyClass(ClassList[I]).Create();
...

но если дочерних классов немного, то городить регистрацию может быть нецелесообразно. Кроме того, общего предка может не быть.
Тогда пишем так:
case IndexStr(Node.NodeName, [TMyClass1.GetXMLNodeName,     TMyClass2.GetXMLNodeName, TMyClass3.GetXMLNodeName]) of
0: Result:=TMyClass1.Create();
1: Result:=TMyClass2.Create(param1);
2: Result:=TMyClass3.Create(param2, param3);
else NotFound();

то есть сами значения строк могут приходить и снаружи, но именно массив  полностью заполняется прямо в теле case

Я правда погорячился, когда сказал, что паттерн используется в хвост и в гриву. Используется он изредка, часто используется другой паттерн, похожий

case IndexOfObject(MyObj, [TMyClass1, TMyClass2, TMyClass2]) of
0: //MyObj is TMyClass1
1: //MyObj is TMyClass2
2: //MyObj is TMyClass3

вместо многократных
if MyObj is TMyClass1 then ...
else  if MyObj is TMyClass2...

Но это уже оффтоп.

И на месте автора я бы для данного примера сделал по-другому, а именно - объявил бы тип-перечисление, и завел бы констатарный массив строк.

type
 TMyOperation = (moOpen, moSend, moETC);

const
 Commands: array[TMyOperation] of string = ("Open", "Send", "ETC");

плюсом является то, что при добавлении команды в перечисление компилятор сам подскажет, куда вставить новую строковую константу


 
Leonid Troyanovsky ©   (2010-04-02 09:48) [29]


> _Юрий   (01.04.10 19:54) [28]

> Требуется создать дочерний объект нужного класса в зависимости
> от имени узла, и вызвать его загрузку.

Т.е., имена, все же, поступают извне.
Я б обратил внимание на 1 метод by Vladimir Titov.

И еще, тут стоило б подумать об использовании
Delphi streaming system.

--
Regards, LVT.


 
oxffff ©   (2010-04-02 12:02) [30]

Решил отдохнуть от Oracle. Написал только что. Сильно не бить.

Идея была свести до использования  

MyCase("1",[
          ["1",procedure  
                   begin
                   showmessage("Fuck stuff by oxffff. Option 1");
                   end],
          ["2",procedure  
                   begin
                   showmessage("Fuck stuff by oxffff. Option 2");
                   end]
          ]);    

Но! Есть ограничения у компилятора Delphi, здесь он совсем гибок.

Придется так

MyCase("1",[
          self["1",procedure  
                   begin
                   showmessage("Fuck stuff by oxffff. Option 1");
                   end],
          self["2",procedure  
                   begin
                   showmessage("Fuck stuff by oxffff. Option 2");
                   end]
          ]);    

Код

TPair=record
Value:string;
Action:TProc;
end;

 TForm2 = class(TForm)
   procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
 protected
 Function GetCaseOption(Value:string;Action:TProc):TPair;
 public
   { Public declarations }
 property CaseOption[Value:string;Action:TProc]:TPair read GetCaseOption;default;
 end;

var
 Form2: TForm2;

procedure MyCase(const Value:string;const Pairs:array of TPair);
var Pair:TPair;
begin
for Pair in Pairs do if Pair.Value=Value then
  begin
  Pair.Action();
  exit;
  end;
end;

function TForm2.GetCaseOption(Value: string; Action: TProc): TPair;
begin
result.Value:=Value;
result.Action:=action;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
MyCase("1",[
          self["1",procedure  
                   begin
                   showmessage("Fuck stuff by oxffff. Option 1");
                   end],
          self["2",procedure  
                   begin
                   showmessage("Fuck stuff by oxffff. Option 2");
                   end]
          ]);        
end;


 
oxffff ©   (2010-04-02 12:03) [31]


>  здесь он совсем гибок.


не совсем гибок. :)


 
oxffff ©   (2010-04-02 12:11) [32]

Поддержка else. :)

procedure MyCase(const Value:string;const Pairs:array of TPair;ElseProc:TProc=nil);
var Pair:TPair;
begin
for Pair in Pairs do if Pair.Value=Value then
  begin
  Pair.Action();
  exit;
  end;
ElseProc();
end;


 
Игорь Шевченко ©   (2010-04-02 12:25) [33]

oxffff ©   (02.04.10 12:02) [30]

Круть! Только зачем ?


 
oxffff ©   (2010-04-02 12:28) [34]


> Игорь Шевченко ©   (02.04.10 12:25) [33]
> oxffff ©   (02.04.10 12:02) [30]
>
> Круть! Только зачем ?


Отдохнуть от Oracle. И возможно взять некоторые идеи к себе в компилятор.
Не могу найти в интернете, но были какие причины на отсутствие case для строк.


 
Sha ©   (2010-04-02 13:07) [35]

> oxffff ©   (02.04.10 12:28) [34]
> Не могу найти в интернете, но были какие причины на отсутствие case для строк.

Целочисленная оптимизация?


 
Dfcz Gegrby   (2010-04-02 14:22) [36]


> oxffff ©   (02.04.10 12:02) [30]

Извращенец. (в хорошем смысле ;) )


 
oxffff ©   (2010-04-02 14:56) [37]


> Sha ©   (02.04.10 13:07) [35]
> > oxffff ©   (02.04.10 12:28) [34]
> > Не могу найти в интернете, но были какие причины на отсутствие
> case для строк.
>
> Целочисленная оптимизация?


Честное слово не помню. Но какое то ощущение осталось.
Пытался найти. Не нашел.
Возможно неоднозначность сравнения например при case sensitive.
То ли unicode. Честное слово не помню.


 
oxffff ©   (2010-04-02 15:07) [38]


> Sha ©   (02.04.10 13:07) [35]
> > oxffff ©   (02.04.10 12:28) [34]
> > Не могу найти в интернете, но были какие причины на отсутствие
> case для строк.
>
> Целочисленная оптимизация?


Вроде после прочтения этого.

http://www.delphifeeds.com/go/s/62355


 
Anatoly Podgoretsky ©   (2010-04-02 15:15) [39]

> oxffff  (02.04.2010 14:56:37)  [37]

Причины конечно были, но они остались в голове идеолога. Да и какая разница, когда case это особая форма it then else if


 
oxffff ©   (2010-04-02 15:35) [40]

Ну и естественно обобщенная версия

TPAIRTYPE<T>=record
Value:T;
Proc:TProc;
end;

CaseAnyTypeClassSupport<T>=class
private
class function GetCaseOption(Value:T;Action:TProc):TPAIRTYPE<T>;static;
public
class procedure MyCase(const Value:T;const Pairs:array of TPAIRTYPE<T>;ElseProc:TProc=nil);static;
class property CaseOption[Value:T;Action:TProc]:TPAIRTYPE<T> read GetCaseOption;default;
end;

uses generics.defaults;

class procedure CaseAnyTypeClassSupport<T>.MyCase(const Value:T;const Pairs:array of TPAIRTYPE<T>;ElseProc:TProc=nil);
var Pair:TPAIRTYPE<T>;
   Comparer:IComparer<T>;
begin
Comparer:=TComparer<T>.Default;
for Pair in Pairs do
  if Comparer.Compare(Value,Pair.Value)=0 then
    begin
    Pair.Proc();
    exit;
    end;
if Assigned(ElseProc) then ElseProc();
end;
class function CaseAnyTypeClassSupport<T>.GetCaseOption(Value:T;Action:TProc):TPAIRTYPE<T>;
begin
Result.Value:=Value;
Result.Proc:=action;
end;

procedure TForm2.FormCreate(Sender: TObject);
var Stuff:CaseAnyTypeClassSupport<string>;
begin
Stuff.MyCase("2",
   [
   Stuff["4",procedure
             begin
             showmessage("Option 1");
             end],
   Stuff["2",procedure
             begin
             showmessage("Option 2");
             end]
   ],procedure
     begin
     showmessage("Else option");
     end);
end;



Страницы: 1 2 вся ветка

Текущий архив: 2010.08.27;
Скачать: CL | DM;

Наверх




Память: 0.59 MB
Время: 0.063 c
6-1224709751
serko
2008-10-23 01:09
2010.08.27
Telnet через Delphi...


2-1273230896
romario
2010-05-07 15:14
2010.08.27
Не работает функция trim


15-1267169309
abhtr
2010-02-26 10:28
2010.08.27
Как сложить данные из одной таблицы


6-1218807638
_koha
2008-08-15 17:40
2010.08.27
Падает сокет усервера на WinAPI - не могу разобраться


2-1265712324
Nilman
2010-02-09 13:45
2010.08.27
Поясните пожалуйста значение свойства TThread.FreeOnTerminate