Форум: "Начинающим";
Текущий архив: 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 к Variantwith 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