批处理文件 "Unbalanced Parenthesis"

Batch File "Unbalanced Parenthesis"

所以我正在尝试制作这个程序:

//@echo off
@title Calculate Caloric Needs
set /p name=What is the name of the individual in question? 
CLS

:START
set /p sex=Is %name% a M(ale) or F(emale)? (M/F) 
CLS
if NOT %sex%==M if NOT %sex%==F ( 
    echo Invalid Selection...Try Again....
    goto START
)

set /p w=What is the target weight of %name%? 
CLS

set /p h=What is the height of %name% IN INCHES? 
CLS

set /p a=What is the age of %name%? 
CLS

if %sex%==M set /a result=66 + (6.23 * %w%) + (12.7 * %h%) - (6.8 * %a%)
if %sex%==F set /a result=655+(4.35*%w%)+(4.7*%h%)-(4.7*%a%)

echo %result% is the caloric intake for %name%.
pause
exit
为了进行故障排除,

@echo off 已被禁用。

这是一个简单的程序,用于计算一些热量摄入量,这些计算逐项计算起来有点困难。

每次我达到需要进行算术计算的程度时,都会发生以下两种情况之一:

  1. 如果我将 set /a 语句包装在 if %sex%==M ( CODE HERE ) 块中,程序将意外退出而不显示错误消息。
  2. 如果我不这样做并且将所有内容都放在一行中(如上面发布的示例代码中所示),那么我会收到消息 Unbalanced Parenthesis 而无需任何进一步解释(感谢 Windows。 ..).

据我所知,从数学上讲括号是完全平衡的。

我试过:

所以我不知道是什么导致了这种奇怪的行为。

您收到的错误消息在您的情况下非常混乱,因为 set /A 命令行中的括号是平衡的,并且在整个命令行未放在括号内的情况下以这种方式工作代码本身。无论如何,将整个 set /A 表达式放在引号之间总是一个好主意,这样圆括号或其他特殊字符都不会造成麻烦。
方括号对 set /A.

没有任何特殊意义

无论如何,错误的根本原因是您使用的是小数,尽管set /A仅支持 32 位空间中的有符号整数运算(请参阅 set /? 的帮助)。在命令提示符 window 中键入 set /A (1.2*3),您将收到相同的错误消息;但删除 . 一切都会好起来的。

一种可能的解决方法是使用定点运算之类的东西,因此在计算过程中将所有内容乘以 10 的整数次方,最后将结果除以 10 的相同次方,或者换句话说,移动在进行计算之前将小数点移到右边,然后再将其移回。

这就是它的样子(我还修复了您代码中的一些其他问题,但请参阅下文):

@echo off
@title Calculate Caloric Needs

cls
set "name=them"
set /P "name=What is the name of the individual in question? "

:START
set "sex="
set /P "sex=Is %name% a M(ale) or F(emale)? (M/F) "
if /I not "%sex%"=="M" if /I not "%sex%"=="F" (
    echo Invalid Selection... Try Again...
    goto :START
)

set "w=0"
set /P "w=What is the target weight of %name%? "

set "h=0"
set /P "h=What is the height of %name% IN INCHES? "
set "h=%h%."            & rem // append a decimal dot to entry in `h`
set "mil=1%h:*.=%"      & rem // store everything behind first dot in `mil`, prepend `1`
set /A "h+=0, mil+=0"   & rem // convert `h` to integer, dismiss fractional part
set "mil=%mil%000"      & rem // pad trailing zeros to `mil`
set "mil=%mil:~,4%"     & rem // extract first four numerals from `mil`
set /A "mil+=5"         & rem // add `5` to `mil` for rounding
if %mil:~,1% GTR 1 set /A "h+=1" & rem // regard carry of previous addition in `h`
set "h=%h%%mil:~-3,-1%" & rem /* append second and third numeral of `mil` to `h`,
                          rem    hence dismissing previously prepended `1`;
                          rem    so `h` holds the height in 100ths of inches now */

set "a=0"
set /P "a=What is the age of %name%? "

rem // quotation marks avoid trouble with parenthesis or other characters;
rem /* all original constants are multiplied by `1000` to avoid fractional parts,
rem    except the factor at `h` which is multiplied by `10` only due to above
rem    implicit multiplication of `h` by 100, then `500` is added for rounding,
rem    and finally, the result is divided by `1000` to remove the previous factors: */
if /I "%sex%"=="M" (
    set /A "result=(66000+(6230*%w%)+(127*%h%)-(6800*%a%)+500)/1000"
) else if /I "%sex%"=="F" (
    set /A "result=(655000+(4350*%w%)+(47*%h%)-(4700*%a%)+500)/1000"
)

echo %result% is the caloric intake for %name%.
pause
exit /B

这是我修复的:

  • setset /P 语法得到改进,整个表达式都在引号之间,因此您避免了特殊字符的麻烦,并且您可以清楚地看到是否有尾随空格;
  • 任何提示值都会被初始化,以避免在用户刚刚按下 RETURN;
  • 时采用之前的值
  • 性别条目的 if 查询已更正,现在通过添加开关 /I 不区分大小写,并且在测试变量为空的情况下不会造成问题引号内的比较表达式;
    顺便说一下,您可能对此类单键输入的 choice 命令感兴趣,因为它甚至不接受任何其他字符;
  • 由于上述定点算法,以英寸为单位的身高条目 h 的值被转换为英寸的百分之一(但体重 w 和年龄 a 仍然被处理作为整数);这是它的工作原理:
    • set "h=%h%.":在h中的条目后加一个点,以确保至少有一个;
    • set "mil=1%h:*.=%":将 h 中第一个点之后的所有内容存储到 mil(小数部分),并在结果前添加 1 以不丢失任何前导零(这对小数部分很重要)一旦转换为数字;
    • set /A "h+=0, mil+=0":将hmil都转换为数值(整数);这会将第一个非数字数字之前的所有内容转换为数字,忽略前导空格但关于符号 +/-(尽管它们无关紧要,因为此处不需要);
    • set "mil=%mil%000":在小数部分后追加 3 个零(前面的 1 仍然存在,因此始终至少有 4 个数字);
    • set "mil=%mil:~,4%":提取前4个字符(所以前缀1再加3个数字);
    • set /A "mil+=5":添加5,所以如果最后一个数字是5或更多,就会出现进位,因此会发生倒数第二个数字的舍入;
    • if %mil:~,1% GTR 1 set /A "h+=1":在h中增加整数部分以防进位超过小数部分;
    • set "h=%h%%mil:~-3,-1%":将h的整数部分和mil中小数部分倒数第二个数字的范围拼接起来存入h;
  • result的公式中的所有常数都乘以1000使小数点消失,除了h乘以10的因数只是,因为h已经是原高度值的100倍;之后结果除以 1000500 的添加仅意味着在除以 1000 时添加 0.5 并且打算在它们之前将 .5.9* 的小数部分四舍五入因整数除法而迷路;
  • exit 命令被 exit /B 替换以终止批处理文件,但不终止拥有的 cmd 实例;

请注意,像 ///**/ 这样的注释在批处理文件中没有特殊含义。 rem 语句给出评论或评论。我在这里使用 rem 中的斜线式注释只是为了在本网站上突出显示一些很酷的语法...


更新

按照,结果本身应该是小数,所以我稍微修改了脚本(下面有描述):

@echo off
@title Calculate Caloric Needs

cls
set "name=them"
set /P "name=What is the name of the individual in question? "

set "male="
choice /C MF /M "Is %name% a M(ale) of F(emale)? "
if not ErrorLevel 2 set "male=Flag"

set "w=0"
set /P "w=What is the target weight of %name% IN POUNDS? "

set "h=0"
set /P "h=What is the height of %name% IN INCHES? "
set "h=%h%."            & rem // append a decimal dot to entry in `h`
set "mil=1%h:*.=%"      & rem // store everything behind first dot in `mil`, prepend `1`
set /A "h+=0, mil+=0"   & rem // convert `h` to integer, dismiss fractional part
set "mil=%mil%000"      & rem // pad trailing zeros to `mil`
set "mil=%mil:~,4%"     & rem // extract first four numerals from `mil`
set /A "mil+=5"         & rem // add `5` to `mil` for rounding
if %mil:~,1% GTR 1 set /A "h+=1" & rem // regard carry of previous addition in `h`
set "h=%h%%mil:~-3,-1%" & rem /* append second and third numeral of `mil` to `h`,
                          rem    hence dismissing previously prepended `1`;
                          rem    so `h` holds the height in 100ths of inches now */

set "a=0"
set /P "a=What is the age of %name% IN YEARS? "

rem // quotation marks avoid trouble with parenthesis or other characters;
rem /* all original constants are multiplied by `1000` to avoid fractional parts,
rem    except the factor at `h` which is multiplied by `10` only due to above
rem    implicit multiplication of `h` by 100, then `500` is added for rounding,
rem    and finally, the result is divided by `1000` to remove the previous factors: */
if defined male (
    set /A "result=66000+(6230*%w%)+(127*%h%)-(6800*%a%)+5"
) else (
    set /A "result=655000+(4350*%w%)+(47*%h%)-(4700*%a%)+5"
)

echo %result:~,-3%.%result:~-3,-1% is the caloric intake for %name%.
pause
exit /B

这是我所做的:

  • 基本的计算公式还是一样的,只是这次省略了除以1000,并且在结果中加入了5进行四舍五入,而不是500 ];但是为了显示结果,最后一个数字被忽略,并且在剩余的最后两个数字之前插入一个小数点 .,因此结果有两个小数位;
  • 性别条目现在由 choice 命令完成,如本答案原始版本中所建议的(见上文),因此不再需要简单地捕获无效结果 choice只接受预定义的键或字符;

根据@aschipfl 的回复,这是因为我试图将 /a 与浮点数一起使用。

我使用 bc for Windows 解决了这个问题。因为现在的命令行应该默认支持像浮点运算这样基本的东西。

那是什么:

if %sex%==M set /a result=66 + (6.23 * %w%) + (12.7 * %h%) - (6.8 * %a%)

现在是:

set bc=bc\bc.exe
if /I "%sex%"=="M" echo 66 + (6.23 * %w%) + (12.7 * %h%) - (6.8 * %a%) | %bc% & echo is the caloric intake required per-day for %name%