В соседней теме участник
Munin предложил (правда, не всем желающим, а ТС) следующую задачку
http://atpp.vstu.edu.ru/cgi-bin/arh_pro ... id_prb=898Однако, мне она показалась достаточно интересной - относительно простой, понятной, годящейся для начала и позволяющей потренироваться в устойчивости к некорректным входным данным. Вот я и взял и написал программку её решения (на языке 1С7.7
, мне так было проще, но это не принципиально, код приводится в теге оффтопика).
(Оффтоп)
Код:
Перем ВходящееВыражение;
Перем м_Ошибка, м_РезультатОшибка;
Функция ДатьРезультат(Знач ПозНач, Знач ПозКон) Далее
//------------------------------------------------------------------------------------------
Функция ДатьПозициюЗакрывающейСкобки(Знач ПозНач)
Счетчик = 1;
Для й = ПозНач + 1 По СтрДлина(ВходящееВыражение) Цикл
ТекСимвол = Сред(ВходящееВыражение, й, 1);
Если ТекСимвол = "(" Тогда Счетчик = Счетчик + 1;
ИначеЕсли ТекСимвол = ")" Тогда Счетчик = Счетчик - 1;
КонецЕсли;
Если Счетчик = 0 Тогда Прервать; КонецЕсли;
КонецЦикла;
Если Счетчик <> 0 Тогда м_Ошибка = 1 КонецЕсли;
Возврат й;
КонецФункции
//------------------------------------------------------------------------------------------
Функция ДатьАргумент(ПозНач)
ПервыйСимвол = Сред(ВходящееВыражение, ПозНач, 1);
Если ПервыйСимвол = "(" Тогда
ПозЗакрывающейСкобки = ДатьПозициюЗакрывающейСкобки(ПозНач);
Результат = ДатьРезультат(ПозНач + 1, ПозЗакрывающейСкобки - 1);
ПозНач = ПозЗакрывающейСкобки + 1;
Иначе
Результат = ПервыйСимвол;
ПозНач = ПозНач + 1;
КонецЕсли;
Возврат Результат;
КонецФункции
//------------------------------------------------------------------------------------------
Функция ДатьРезультат(Знач ПозНач, Знач ПозКон)
Если м_Ошибка = 1 Тогда Возврат м_РезультатОшибка КонецЕсли;
Пока Сред(ВходящееВыражение, ПозНач, 1) = "(" Цикл
Если ДатьПозициюЗакрывающейСкобки(ПозНач) = ПозКон Тогда
ПозНач = ПозНач + 1;
ПозКон = ПозКон - 1;
Иначе
Прервать;
КонецЕсли;
КонецЦикла;
Если ПозНач > ПозКон Тогда
м_Ошибка = 1;
Возврат м_РезультатОшибка;
ИначеЕсли ПозНач = ПозКон Тогда
Возврат Сред(ВходящееВыражение, ПозНач, 1);
КонецЕсли;
Результат = "";
Пока ПозНач < ПозКон Цикл
Если Результат = "" Тогда
ЛевыйАргумент = ДатьАргумент(ПозНач);
Иначе
ЛевыйАргумент = Результат;
КонецЕсли;
СимволОперации = Сред(ВходящееВыражение, ПозНач, 1);
ПозНач = ПозНач + 1;
Если (СимволОперации = "+") или (СимволОперации = "-") Тогда
// правый аргумент берем до конца входящей строки
ПравыйАргумент = ДатьРезультат(ПозНач, ПозКон);
ПозНач = ПозКон + 1;
Иначе
// умножаем и делим только на ближайший аргумент
ПравыйАргумент = ДатьАргумент(ПозНач);
КонецЕсли;
Результат = "(" + ЛевыйАргумент + "," + ПравыйАргумент + ")";
Если СимволОперации = "+" Тогда Результат = нрег(" ADD") + Результат;
ИначеЕсли СимволОперации = "-" Тогда Результат = нрег(" SUB") + Результат;
ИначеЕсли СимволОперации = "*" Тогда Результат = нрег(" MUL") + Результат;
ИначеЕсли СимволОперации = "/" Тогда Результат = нрег(" DIV") + Результат;
Иначе м_Ошибка = 1;
КонецЕсли;
КонецЦикла;
Возврат ?(м_Ошибка = 1, м_РезультатОшибка, Результат);
КонецФункции
//------------------------------------------------------------------------------------------
Процедура Сформировать()
м_Ошибка = 0;
м_РезультатОшибка = "Ошибка";
// первично форматируем входящее выражение - убираем пробелы, в верхний регистр
ВходящееВыражение = ВРЕГ(СтрЗаменить(СокрЛП(ВыбВходящееВыражение), " ", ""));
ВыбРезультатВыражение = СокрЛП(ДатьРезультат(1, СтрДлина(ВходящееВыражение)));
КонецПроцедуры
Хотелось бы обсудить:
1) алгоритмические моменты
2) протестировать реакцию на разнообразно-некорректные входные данные
3) протестировать правильность вычислений (могу написать парсер выходного языка и вычисление значения выражений со случайными входными аргументами, и сравнить его с вычислением значения из исходной строки)
Для пунктов 2 и 3 можно предлагать навороченные строки в качестве исходных данных, буду выдавать результат.