Обход двусмысленности при вычислениях командой SET

Как ранее было указано, команда set имеет ключ /A, который позволяет производить целочисленные операции: умножение, сложение, деление, получение остатка, логические операции "И", "ИЛИ", "НЕ", исключительное "ИЛИ" (xor), сдвиг влево и вправо.
Довольно серьезный набор операций, но он еще более расширен по возможности "потребления" числовых форматов.
Например, число 13, будучи записанным, как 013 будет означать число в восьмиричной системе, а в десятичной это будет 1110.
Если мы запишем число 13, как 13, то оно будет воспринято, как число в десятичной системе и естественно будет равно 1310.
А вот если мы запишем 13, как 0x13, то это будет означать число в шестнадцатиричной системе счисления и будет равно 1910.
Вот такое богатство доступно нам при работе с числами. Обратной стороной такого, является путаница и неоднозначность при работе с числами в десятичной системе, которую я вам и покажу, как обойти.

Предположим, у нас есть ряд чисел: "03237419024805980398610760183703765348601834702857061837430"
Нам надо найти сумму всех трехзначных чисел, то есть проскользить по всему списку, выхватывая трехзначные числа и суммируя их друг с другом.

Начнем, пожалуй.
Чтобы выхватить нужный кусок из строки, воспользуемся командой :~
Общий вид выглядит следующим образом: %Env_Var:~Start,Count%, где Start - это начальный символ в строке, а Count - количество, которое надо взять начиная от Start
Попробуйте: echo %time:~0,5%
сравните с echo %time%
Поэкспериментируйте, например с переменной path, она подлиннее.

Чтобы последовательно перебирать, нам надо обеспечить выполнение 2х условий:
1) Надо запрограммировать бегущий указатель текущей позиции в строке
2) Вовремя обнаружить, что строка закончилась
Казалось бы, что тут делать ?


@echo off
set ABCD=03237419024805980398610760183703765348601834702857061837430
set Summ=0
set Tvar=0
setlocal ENABLEDELAYEDEXPANSION
for /l %%a in (0,3,90) do (
set Tvar=!ABCD:~%%a,3!
if "!Tvar!"=="" goto CycleOut
set /a Summ=!Summ!+!TVar!
)
:CycleOut
echo Out reached: Summ=!Summ!

И получаем кучу ошибок, потому что интерпретатор при попытке интерпретировать, например число 059 на 5ом шаге, спотыкается, так как число 9 в восьмеричной системе счисления отсуствует. Ах, да, число 059, воспринимается не как 59, а как 598, отсюда и сбой.
Так как же отрывать лидирующий нолик ?
Первое, что приходит в голову: это соорудить конструкцию из FOR, где разделителем будет "0", например:
For /f "delims=0 tokens=*" %%z in (!Tvar!) do ...
и в случае с лидирующим нулем, мы получим, что надо, но в случае с нулем посередине или в конце... число будет разрезано.

Определенно, For надо как-то усложнить, чтобы он поумнел и резал только первый ноль, а если ноль посередине, то не трогал.
Чтобы For резал всегда где надо, давайте его обеспечим материалом, чтобы он никогда не оставался без работы, а именно, если у нас есть лидирующий нолик, то туда ему и дорога, For его отрежет, а вот если в числе лидирующего нолика нет... то мы ему его дадим.

Важно! Когда вы внутри цикла определяете переменную, все вслед за ней буквы переменных будут переопределены, то есть если в первых скобках вы использовали a,b,c и d, а в середине указали начать работу с "b", то переменные: от "b" до "z" будут переопределены, а первичные значения b,c и d будут утеряны. Не забывайте об этом.

Переписываем For с учетом полученных знаний.
for /f "delims=0 tokens=*" %%z in ("0!Tvar!") do set Tvar=%%z
... и вставлем его перед операцией сложения.


@echo off
set ABCD=03237419024805980398610760183703765348601834702857061837430
set Summ=0
set Tvar=0
setlocal ENABLEDELAYEDEXPANSION
for /l %%a in (0,3,90) do (
set Tvar=!ABCD:~%%a,3!
if "!Tvar!"=="" goto CycleOut
for /f "delims=0 tokens=*" %%z in ("0!Tvar!") do set Tvar=%%z
set /a Summ=!Summ!+!TVar!
)
:CycleOut
echo Out reached: Summ=!Summ!

Вуаля, мы победили, уйдя от неопределенности вносимой лидирующим ноликом.

Hosted by uCoz