Как можно поместить в массив или таблицу значений
каждый элемент арифметического выражения, например:
наше выражение: 623 + 728 * 51-2

Результирующая таблица:
ТаблицаЗначений(Индекс1,623)
ТаблицаЗначений(Индекс1,+)
ТаблицаЗначений(Индекс1,728)
ТаблицаЗначений(Индекс1,*)
ТаблицаЗначений(Индекс1,51)
ТаблицаЗначений(Индекс1,-)
ТаблицаЗначений(Индекс1,2)

```1c
    Процедура Кнопка3Нажатие(Элемент)
    ЧтоСложить="623 + 728 * 51-2"; // строка формулы

    Безпробелов = СтрЗаменить(ЧтоСложить," ",");
    //УбратьНечисловые(Безпробелов);
    Разделитель = "+";
    МассивВыражений =

    РазложитьСтрокуВМассивПодстрок(Безпробелов,Разделитель,Истина);

    КонецПроцедуры

    Функция РазложитьСтрокуВМассивПодстрок(Знач Строка, Знач Разделитель = ",",

    Знач ПропускатьПустыеСтроки = Неопределено) Экспорт

    Результат = Новый Массив;

    // для обеспечения обратной совместимости
    Если ПропускатьПустыеСтроки = Неопределено Тогда
    ПропускатьПустыеСтроки = ?(Разделитель = " ", Истина, Ложь);
    Если ПустаяСтрока(Строка) Тогда
    Если Разделитель = " " Тогда
    Результат.Добавить(");
    КонецЕсли;
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;
    //

    Позиция = Найти(Строка, Разделитель); //+ или -
    Пока Позиция > 0 Цикл
    Подстрока = Лев(Строка, Позиция - 1);
    Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
    Результат.Добавить(Подстрока);
    Результат.Добавить(Сред(Строка, Позиция, 1));
    КонецЕсли;
    Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
    Позиция = Найти(Строка, Разделитель);
    КонецЦикла;

    Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Строка) Тогда
    Результат.Добавить(Строка);
    КонецЕсли;

    Возврат Результат;

    КонецФункции
```

Не могу придумать как можно распарсить. Думается, что функцию нужно вызывать рекурсивно, но как?

Смысл задачи в том, что операции * и / не должны иметь более высокий приоритет перед + и - в выражении, тоесть в выражении 623 + 728 * 51-2
сначала выполяется 623+728, затем этот результут *51 и минус 2.
Вот и думаю для ентих целей по типу рекурсии.....
---
Не люблю давать готовые решения, но задача прикольная )

```1c
    Процедура КнопкаВыполнитьНажатие(Кнопка)
    Если Выражение = " Тогда
    Выражение = "623 + 728 * 51-2";
    КонецЕсли;
    Выражение = СтрЗаменить(Выражение," ",");
    МассивОпераций = Новый Массив;
    МассивОпераций.Добавить("+");
    МассивОпераций.Добавить("-");
    МассивОпераций.Добавить("*");
    МассивОпераций.Добавить("/");
    МассивИтог = РазложитьВыражениевВТаблицу(Выражение, МассивОпераций);
    КонецПроцедуры

    Функция РазложитьВыражениевВТаблицу(Выражение, МассивОпераций)
    МассивИтог = Новый Массив;
    ТекущаяПозицияНачало = 1;
    ЧислоСимволов = СтрДлина(Выражение);
    Для i=1 по ЧислоСимволов Цикл
    ТекСимвол = Сред(Выражение,i,1);
    Если МассивОпераций.Найти(ТекСимвол) <> Неопределено Тогда
    ЧислоСтрокой = Сред(Выражение,ТекущаяПозицияНачало,?((i - ТекущаяПозицияНачало)=0,1,(i - ТекущаяПозицияНачало)));
    МассивИтог.Добавить(ЧислоСтрокой);
    МассивИтог.Добавить(ТекСимвол);
    ТекущаяПозицияНачало = i+1;
    ИначеЕсли i = ЧислоСимволов Тогда
    ЧислоСтрокой = Сред(Выражение,ТекущаяПозицияНачало,?((i - ТекущаяПозицияНачало)=0,1,(i - ТекущаяПозицияНачало)));
    МассивИтог.Добавить(ЧислоСтрокой);
    КонецЕсли;
    КонецЦикла;
    Возврат МассивИтог;
    КонецФункции
```
---
Manticor, Я бы попробовал слева на право посимвольно пытаться преобразовывать в число. При Возникновении ошибки будит понятно что это "+","-" итд и при каждой ошибке можно добавлять левую часть в тз.
---
Не люблю давать готовые решения, но задача прикольная )

```1c
    Процедура КнопкаВыполнитьНажатие(Кнопка)
    Если Выражение = " Тогда
    Выражение = "623 + 728 * 51-2";
    КонецЕсли;
    Выражение = СтрЗаменить(Выражение," ",");
    МассивОпераций = Новый Массив;
    МассивОпераций.Добавить("+");
    МассивОпераций.Добавить("-");
    МассивОпераций.Добавить("*");
    МассивОпераций.Добавить("/");
    МассивИтог = РазложитьВыражениевВТаблицу(Выражение, МассивОпераций);
    КонецПроцедуры

    Функция РазложитьВыражениевВТаблицу(Выражение, МассивОпераций)
    МассивИтог = Новый Массив;
    ТекущаяПозицияНачало = 1;
    ЧислоСимволов = СтрДлина(Выражение);
    Для i=1 по ЧислоСимволов Цикл
    ТекСимвол = Сред(Выражение,i,1);
    Если МассивОпераций.Найти(ТекСимвол) <> Неопределено Тогда
    ЧислоСтрокой = Сред(Выражение,ТекущаяПозицияНачало,?((i - ТекущаяПозицияНачало)=0,1,(i - ТекущаяПозицияНачало)));
    МассивИтог.Добавить(ЧислоСтрокой);
    МассивИтог.Добавить(ТекСимвол);
    ТекущаяПозицияНачало = i+1;
    ИначеЕсли i = ЧислоСимволов Тогда
    ЧислоСтрокой = Сред(Выражение,ТекущаяПозицияНачало,?((i - ТекущаяПозицияНачало)=0,1,(i - ТекущаяПозицияНачало)));
    МассивИтог.Добавить(ЧислоСтрокой);
    КонецЕсли;
    КонецЦикла;
    Возврат МассивИтог;
    КонецФункции
```
---
mymyka, спасибо, понятно с этим), тперь пытаюсь вычислить последовательно без учета приоритета операций. Со врменным хранением значений трудности

```1c
    Процедура КнопкаВыполнитьНажатие(Кнопка)
    Если Выражение = " Тогда
    Выражение = "623 + 728 * 51-2";
    КонецЕсли;

    Выражение = СтрЗаменить(Выражение," ",");
    МассивОпераций = Новый Массив;
    МассивОпераций.Добавить("+");
    МассивОпераций.Добавить("-");
    МассивОпераций.Добавить("*");
    МассивОпераций.Добавить("/");
    МассивИтог = РазложитьВыражениевВТаблицу(Выражение, МассивОпераций);
    ///////////////////////////
    Для сч=0 По МассивИтог.Количество()-1 Цикл
    Если сч <=2 Тогда
    Рез1 = Строка(рез1) + МассивИтог[сч];
    иначе
    Рез2 = Строка(рез2) + МассивИтог[сч];

    КонецЕсли;
    итог = вычислить( строка(рез1)+Строка(Рез2));

    КонецЦикла;
    Сообщить(рез1);
    Сообщить(итог);

    КонецПроцедуры
```
---
лабы в универах уже не на C++ пишут, а на 1С? ))

http://program.rin.ru/razdel/html/941.html
---
У меня нескромный вопрос - а вам зачем?
---
Какие еще действия будут? Скобки, возведение в степень? )))
---
рабочий вариант )

```1c
    Процедура КнопкаВыполнитьНажатие(Кнопка)
    Если Выражение = " Тогда
    Выражение = "623 + 728 * 51-2";
    КонецЕсли;
    Выражение = СтрЗаменить(Выражение," ",");
    МассивОпераций = Новый Массив;
    МассивОпераций.Добавить("+");
    МассивОпераций.Добавить("-");
    МассивОпераций.Добавить("*");
    МассивОпераций.Добавить("/");
    МассивИтог = РазложитьВыражениевВТаблицу(Выражение, МассивОпераций);
    ПромежуточныйИтог = ";
    ТекущееВыражение = ";
    Для Каждого Элемент из МассивИтог Цикл
    Если ПромежуточныйИтог = " Тогда
    ПромежуточныйИтог = Элемент;
    Продолжить;
    КонецЕсли;

    Если НЕ ЭтоЧисло(МассивОпераций, Элемент) Тогда
    ТекущееВыражение = Строка(ПромежуточныйИтог) + Элемент;
    Иначе
    ТекущееВыражение = ТекущееВыражение + Элемент;
    ПромежуточныйИтог = Вычислить(ТекущееВыражение);
    Сообщить(ТекущееВыражение+"="+Строка(ПромежуточныйИтог));
    КонецЕсли;
    КонецЦикла;
    Сообщить("Итого: "+ПромежуточныйИтог);
    КонецПроцедуры

    Функция ЭтоЧисло(МассивОпераций, Элемент)
    Возврат ?(МассивОпераций.Найти(Элемент) = Неопределено,Истина,Ложь);
    КонецФункции

    Функция РазложитьВыражениевВТаблицу(Выражение, МассивОпераций)
    МассивИтог = Новый Массив;
    ТекущаяПозицияНачало = 1;
    ЧислоСимволов = СтрДлина(Выражение);
    Для i=1 по ЧислоСимволов Цикл
    ТекСимвол = Сред(Выражение,i,1);
    Если МассивОпераций.Найти(ТекСимвол) <> Неопределено Тогда
    ЧислоСтрокой = Сред(Выражение,ТекущаяПозицияНачало,?((i - ТекущаяПозицияНачало)=0,1,(i - ТекущаяПозицияНачало)));
    МассивИтог.Добавить(ЧислоСтрокой);
    МассивИтог.Добавить(ТекСимвол);
    ТекущаяПозицияНачало = i+1;
    ИначеЕсли i = ЧислоСимволов Тогда
    ЧислоСтрокой = Сред(Выражение,ТекущаяПозицияНачало,?((i - ТекущаяПозицияНачало)=0,1,(i - ТекущаяПозицияНачало)));
    МассивИтог.Добавить(ЧислоСтрокой);
    КонецЕсли;
    КонецЦикла;
    Возврат МассивИтог;
    КонецФункции
```
---
mymyka, почему то выражение Вычислить(1003-3) уже не работает а Вычислить(1002-3) уже дает релуьтат
тоесть с малыми числами код работает, с 3-х знаками почему то нет))
---
Скорее всего из-за формата строкового представления числа, выше четырех знаков добавляется разделитель между 1 и 000.
---
mymyka, ПромежуточныйИтог = Формат(Вычислить(ТекущееВыражение), "ЧДЦ=0; ЧГ=0");
так вроде не ругается. Спасибо всем огромое за поддержку))
---
mymyka, Экспериментирую со скобками в формуле. Пытаюсь сделать сначала действие в них, затем уже с учетом полученого выражения все остальное.

Функцией скобки вычислил выраженеи в скобках. Как теперь можно склеить резуьтат скобок с общей формулой для вычисления?

```1c
    &НаКлиенте
    Процедура Команда2(Команда)
    СписокЧисел = новый СписокЗначений();
    СписокЧисел.Добавить("0");
    СписокЧисел.Добавить("1");
    СписокЧисел.Добавить("2");
    СписокЧисел.Добавить("3");
    СписокЧисел.Добавить("4");
    СписокЧисел.Добавить("5");
    СписокЧисел.Добавить("6");
    СписокЧисел.Добавить("7");
    СписокЧисел.Добавить("8");
    СписокЧисел.Добавить("9");
    СписокЧисел.Добавить(",");

    СписокДействий = новый СписокЗначений();
    СписокДействий.Добавить("+");
    СписокДействий.Добавить("-");
    СписокДействий.Добавить("*");
    СписокДействий.Добавить("/");
    СписокДействий.Добавить("(");
    СписокДействий.Добавить(")");

    Попытка
    ЧтоСложить="5 * (7+3*2)/1000"; //"623 + 728 * 51-2";
    Безпробелов = СтрЗаменить(ЧтоСложить," ",");

    МассивИтог = Разложить(Безпробелов,СписокЧисел,СписокДействий);
    Скоб = Скобки(МассивИтог);
    //считаем
    //считаем
    ПромежуточныйИтог = ";
    ТекущееВыражение = ";
    Для Каждого Элемент из Скоб Цикл
    Если ПромежуточныйИтог = " Тогда
    ПромежуточныйИтог = Элемент.Значение;
    Продолжить;
    КонецЕсли;

    Если НЕ ЭтоЧисло(СписокДействий, Элемент.Значение) Тогда
    ТекущееВыражение = Строка(ПромежуточныйИтог) + Элемент.Значение;
    Иначе
    ТекущееВыражение = ТекущееВыражение + Элемент.Значение;
    ПромежуточныйИтог = Вычислить(ТекущееВыражение);
    Сообщить(ТекущееВыражение+"="+Строка(ПромежуточныйИтог));
    КонецЕсли;
    КонецЦикла;
    Сообщить("Итого: "+ПромежуточныйИтог);
    Элементы.Результ.Заголовок = "Результат = "+ПромежуточныйИтог;

    Исключение
    Сообщить(ОписаниеОшибки());

    КонецПопытки;

    КонецПроцедуры

    &НаСервере
    Функция Скобки(МассивИтог)
    ПромежуточныйИтог = ";
    ТекущееВыражение = ";
    ИтогПром = ";
    Индекс =0;
    ТаблЗнач = новый ТаблицаЗначений;
    ТаблЗнач.Колонки.Добавить("Значение");

    Для Индекс = 0 По МассивИтог.Количество()-1 Цикл
    Если МассивИтог[Индекс].Значение = "(" Тогда
    Пока МассивИтог[Индекс].Значение <> ")" Цикл
    //ИтогПром = ИтогПром+МассивИтог[Индекс].Значение;
    Если МассивИтог[Индекс].Значение = "(" Тогда
    Индекс = Индекс+1;
    Продолжить;
    Иначе
    СтрокаТаблЗнач = ТаблЗнач.Добавить();
    СтрокаТаблЗнач.Значение = МассивИтог[Индекс].Значение;
    Индекс = Индекс+1;
    КонецЕсли;
    КонецЦикла;
    КонецЕсли;

    Если Индекс >= МассивИтог.Количество()-1 тогда
    Продолжить;
    КонецЕсли;
    КонецЦикла;

    Возврат ТаблЗнач;
    КонецФункции

    &НаСервере
    Функция ЭтоЧисло(МассивОпераций, Элемент)

    Возврат ?(МассивОпераций.НайтиПоЗначению(Элемент) = Неопределено,Истина,Ложь);

    КонецФункции

    &НаСервере
    Функция Разложить(Безпробелов,СписокЧисел, СписокДействий)
    ТаблЗнач = новый ТаблицаЗначений;
    ТаблЗнач.Колонки.Добавить("Значение");

    Пока СтрДлина(Безпробелов) <> 0 цикл

    Если СписокДействий.НайтиПоЗначению(Лев(Безпробелов,1)) <> Неопределено тогда //если это действие
    //Это значение, у него длина вегда 1 символ
    СтрокаТаблЗнач = ТаблЗнач.Добавить();
    СтрокаТаблЗнач.Значение = Лев(Безпробелов,1);
    Безпробелов = прав(Безпробелов, СтрДлина(Безпробелов) - 1); //уберем из строки определенную часть

    Продолжить;
    ИначеЕсли СписокЧисел.НайтиПоЗначению(Лев(Безпробелов,1)) <> Неопределено Тогда //если это число
    НашлиЧисло = ложь;
    ДлинаЧисла = 1;
    //это число, его длину еще надо найти
    Пока СтрДлина(Безпробелов) >= ДлинаЧисла Цикл
    Если СписокЧисел.НайтиПоЗначению(сред(Безпробелов, ДлинаЧисла,1)) = Неопределено тогда //этот символ не относится к числу
    СтрокаТаблЗнач = ТаблЗнач.Добавить();
    СтрокаТаблЗнач.Значение = Лев(Безпробелов, ДлинаЧисла - 1);
    Безпробелов = прав(Безпробелов, СтрДлина(Безпробелов) - ДлинаЧисла+1); //уберем из строки определенную часть
    НашлиЧисло = истина;

    Прервать;
    КонецЕсли;
    ДлинаЧисла = ДлинаЧисла + 1;
    КонецЦикла;
    Если не НашлиЧисло тогда
    //если попали сюда значит все остальное число
    СтрокаТаблЗнач = ТаблЗнач.Добавить();
    СтрокаТаблЗнач.Значение = Безпробелов;
    Безпробелов = ";
    КонецЕсли;
    иначе
    Сообщить("Не корректный символ в формуле", СтатусСообщения.Важное);
    Прервать;
    КонецЕсли;
    КонецЦикла;

    //Выведим результатДля просмотра
    //Для каждого СтрокаТаблЗнач из ТаблЗнач цикл
    // Сообщить(СтрокаТаблЗнач.Значение);
    //КонецЦикла;
    Возврат ТаблЗнач;
    КонецФункции
```
---
Manticor, любое арифметическое выражение сначала следует преобразовать в обратную польскую запись, а затем вычислить на стеке. Учитывается приоритет операций и скобки.

Пример 1:

Выражение: А + Б * С
Обратная запись: АБС*+

Пример 2:

Выражение: (А + Б) * С
Обратная запись: АБ+С*
---
Запоздалое предложение но все же вот :)

```1c
    Процедура ВыполнитьНажатие()
    Выражение = "623 + 728 * 51-2";
    Выражение = СтрЗаменить(Выражение," ",");

    МассивСпецСимволов = Новый Массив;
    МассивСпецСимволов.Добавить("+");
    МассивСпецСимволов.Добавить("-");
    МассивСпецСимволов.Добавить("*");
    МассивСпецСимволов.Добавить("/");

    Для каждого СпецСимвол Из МассивСпецСимволов Цикл
    Выражение = СтрЗаменить(Выражение,СпецСимвол,";");
    КонецЦикла;

    МассивЧисел = ЗначениеИзСтрокиВнутр("{"#",51e7a0d2-530b-11d4-b98a-008048da3034,{0,{"N"," + СтрЗаменить(Выражение, ";", "},{"N",") + "}}}");
    КонецПроцедуры
```

проверено! работает.
---
SamNeSvoy, МассивЧисел = ЗначениеИзСтрокиВнутр("{""#"",51e7a0d2-530b-11d4-b98a-008048da3034,{0,{""N""," + СтрЗаменить(Выражение, ";", "},{""N"",") + "}}}");
Я даже функции такой не знал, что существует, это даже сожнее выражений в Perl)))
Поясните пожалуйста про символы внутри и саму функцию))
---
Manticor, Функция обычная, еще со времен семерки известная.
Идея и реализация не моя. Взята от сюда Про быстрые массивы
ИМХО взяли массив и его ЗначениеВСтрокуВнутр(<Значение>). Посмотрели результирующую строку, сделали обратное. Только сложность будет с непримитивными типами. С числами, как в данном случае, проще: "N" - определяет тип.
---
Обходищь строку посимволбно, используешь следующую функцию

```1c
    Функция ЭтоЧисло(СимволПроверки, СРазделителем=Истина)

    ЭтоЧисло=Ложь;

    КодСимволаПроверки=КодСимвола(СимволПроверки, 1);

    Если КодСимволаПроверки>=48 И КодСимволаПроверки<=57 Тогда

    ЭтоЧисло=Истина;

    КонецЕсли;

    Если СРазделителем И (НЕ ЭтоЧисло) Тогда

    Если КодСимволаПроверки=44 ИЛИ КодСимволаПроверки=46 Тогда

    ЭтоЧисло=Истина;

    КонецЕсли;

    КонецЕсли;

    Возврат ЭтоЧисло;

    КонецФункции
```

Пока истина - число. Ложь новая строка ТЗ с символом операции... и снова новая строка ТЗ
---
Для приоритета операций в ТЗ добавляешь 2 колонки "Приоритет" числа - 1, + или - - 2, * или / - 3
и колонку НомерСтрокиПервоначально и в конце сортируешь по ним...
---
Можно проще:
Строка = "623 + 728 * 51-2";
Строка = СтрЗаменить(Строка, " ", "");
Строка = СтрЗаменить(Строка, "+", Символы.ПС + "+" + Символы.ПС);
Строка = СтрЗаменить(Строка, "-", Символы.ПС + "-" + Символы.ПС);
Строка = СтрЗаменить(Строка, "/", Символы.ПС + "/" + Символы.ПС);
Строка = СтрЗаменить(Строка, "*", Символы.ПС + "*" + Символы.ПС);
Массив = Новый Массив;
Для НомерСтроки = 1 По СтрЧислоСтрок(Строка) Цикл
 Массив.Добавить(СтрПолучитьСтроку(Строка, НомерСтроки));
КонецЦикла;
---
1. Вспомните про приоритет выполнения операций.
2. Дерево вам поможет, соответственно обход делаем по дереву...
3. В УПП есть пример разбора, если не ошибаюсь то в блоке бюджетирования.
---
apatyukov, В УПП есть пример разбора, если не ошибаюсь то в блоке бюджетирования
Скажите пожалуйста в каком именно модуле можно посмотреть пример?