【问题标题】:Batch File "Unbalanced Parenthesis"批处理文件“不平衡括号”
【发布时间】:2016-07-14 13:01:27
【问题描述】:

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

//@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 "result=66 + (6.23 * %w%) + (12.7 * %h%) - (6.8 * %a%)"set /a [result=66 + (6.23 * %w%) + (12.7 * %h%) - (6.8 * %a%)]
  • 转义算术set /a result=66 + ^(6.23 * %w%^) + ^(12.7 * %h%^) - ^(6.8 * %a%^)中使用的部分或全部括号
  • 为了测试set /a result=66 + (6.23 * %w%)而减少括号的数量。 如果我完全使用set /a result=66 + (6.23 * %w%),我实际上可以将语句包装在if ( CODE HERE ) 块中并让它实际返回一个错误值。虽然报错还是Unbalanced Parenthesis...
  • 加长或缩短算术本身的空格数set /a result=66+(6.23*%w%)+(12.7*%h%)-(6.8*%a%) VS。 set /a result=66 + (6.23 * %w%) + (12.7 * %h%) - (6.8 * %a%)
  • 以上所有组合

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

【问题讨论】:

  • 您使用的是浮点数,但set /A 仅支持整数运算!顺便一提; // 不是批处理文件中的注释,请改用rem...
  • Ugg,这是一个愚蠢的限制。考虑到 Windows 已经走了多远。另外,我知道// 不是批量评论。我习惯了 C#,它只是用于故障排除的快捷方式。
  • w的重量单位是多少?
  • @aschipfl 磅。在这种情况下,我没有也仍然不打算在存储库或任何东西上分享最终结果,所以我住在美国,磅是隐含这种计算的标准计量单位。跨度>

标签: windows batch-file windows-7


【解决方案1】:

您收到的错误消息在您的情况下非常令人困惑,因为set /A 命令行中的括号是平衡的,并且如果整个命令行没有放在其括号内的代码块内自己的。无论如何,将整个 set /A 表达式放在引号之间总是一个好主意,这样括号或其他特殊字符都不会造成麻烦。
方括号对set /A 没有任何特殊意义。

无论如何,错误的根本原因是您使用小数,尽管set /A 仅支持 32 位房间中的有符号整数算术(请参阅set /? 的帮助) )。在命令提示符窗口中输入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 次原始高度值;之后结果除以1000;添加500 仅意味着在除以1000 时添加0.5,并且旨在将小数部分从.5 向上舍入到.9*,以免因整数除法而丢失;李>
  • exit 命令被替换为exit /B 以终止批处理文件而不是拥有的cmd 实例;

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


更新

根据comment by the original poster,结果本身应该是一个小数,所以我稍微修改了脚本(下面是描述):

@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 只接受预定义的键或字符;

【讨论】:

  • 我尝试了您的解决方案,虽然它适用于批处理,但出于我的目的,我需要完整的浮点数(因此,如果 1 是所有数字的值并且选择了男性,我需要78.13 不是 78)。
  • 见我的update:结果现在是一个带两位小数的小数...
  • 更新确实使程序现在可以使用小数。这显然是正确答案,我将其标记为正确答案。尽管这超出了我的想象,但我不确定是否更愿意使用 bc.exe。呵呵。从现在开始,我正在听取你对格式和你有什么的建议,以及实施选择(我实际上不知道存在)作为这种事情的默认设置。
  • 谢谢!我发现了一个我在an edit(两个脚本)中修复的问题,其中h 的舍入没有传播到整数部分,例如。 g. 输入7.996 被错误地四舍五入为7.00 而不是8.00;在我的last edit 中,我试图解释这种小数到定点数的转换是如何工作的——我希望它会有所帮助......
【解决方案2】:

根据@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%

【讨论】:

  • 我不完全确定您为什么要首先在命令行上进行算术运算,但您可能需要考虑使用 Powershell 而不是旧的命令行解释器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-05
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多