Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];

Вниз

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;


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

Повторюсь.
Если у delphi компилятор  чуть лучше. то можно было написать так.

with Stuff do
MyCase("2",
  [
  ["4",procedure
            begin
            showmessage("Option 1");
            end],
  ["2",procedure
            begin
            showmessage("Option 2");
            end]
  ],procedure
    begin
    showmessage("Else option");
    end);


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

oxffff ©   (02.04.10 15:35) [40]

if SameText(foo,"FOO") then
 ShowMessage("FOO")
else if SameText(foo,"BAR") then
 ShowMessage("BAR")
else
 ShowMessage("Not FOO nor BAR")


Чутка короче получилось ;)


 
oxffff ©   (2010-04-02 16:19) [43]


> Игорь Шевченко ©   (02.04.10 15:42) [42]
> oxffff ©   (02.04.10 15:35) [40]
>
> if SameText(foo,"FOO") then
>  ShowMessage("FOO")
> else if SameText(foo,"BAR") then
>  ShowMessage("BAR")
> else
>  ShowMessage("Not FOO nor BAR")
>
> Чутка короче получилось ;)


Только с подтипами у Вас дополнительные раздумья будут.
Например Mycase можно написать, чтобы обрабатывал конструкции вида

var a:Tobject;

a:=Tform.create;

case a.classtype of
Tobject: ...
TComponent: ...
TCustomForm: ..
TForm:  ...      <-выполняется это.
end;

А с if выстраивать порядок сравнения придется программисту. ;)


 
Игорь Шевченко ©   (2010-04-02 16:45) [44]

oxffff ©   (02.04.10 16:19) [43]

так вопрос был про строки...
вот в oracle есть case по строкам ;)


 
имя   (2010-04-02 17:07) [45]

Удалено модератором



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

Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.6 MB
Время: 0.065 c
15-1272627412
12
2010-04-30 15:36
2010.08.27
EDBEngineError. Cannot load driver. Что можно сделать?


2-1267556430
AntonioBanderas
2010-03-02 22:00
2010.08.27
Доступ к данным БД Oracle


15-1274270972
Cerberus
2010-05-19 16:09
2010.08.27
Практика в EPAM.


2-1271248525
De:Light
2010-04-14 16:35
2010.08.27
Загрузка и анализ


2-1274209434
Сид
2010-05-18 23:03
2010.08.27
Проверить значение TDBLookupComboBox





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский