为什么 Tcl expr 认为某个数字是"empty",而它实际上不是空的?



>问题陈述

我正在从未知来源导入一组坐标,我没有权限查看该坐标。

set yMin [lindex [lindex $bbox 0] 1]
puts "yMin: <$yMin>"

它工作正常。

yMin: <-6.14999999999999e-02>

括号用于检查是否有任何空格甚至隐藏的制表符。但是,如果yMin乘以任何数字(例如 0.5),则会出错。

set Y2 [expr {0.5 * $yMin}]

不能使用空字符串作为"*">
的操作数,同时执行"expr {0.5 * $yMin}">
从"集合 Y2 [expr {0.5 * $yMin}]"中调用

即使只打印了yMin,它仍然具有空操作数错误。

set Y1 [expr $yMin]
puts "Y1: <$Y1>"

表达式 " 中的空表达式(解析表达式 ")
从"expr $yMin"中调用">
从"集合 Y1 [expr $yMin]"中调用

但是有一个有趣的测试。如果添加大括号,它就可以工作!

set Y1 [expr {$yMin}]
puts "Y1: <$Y1>"

Y1:<-0.06149999999999999999>


如何重现问题

感谢格伦·杰克曼(见下面的回复),

% set bbox {{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}}
{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}
% set yMin [lindex [lindex $bbox 0] 1]
-6.149999999999999e-02
% expr {1 + $yMin}
0.9385

实际上,这似乎无法重现问题(这就是我有这篇文章的原因)。但它至少可以是一个模板。


试错

以下代码用于检查它是否真的为空。事实证明它不是空的。

if {$yMin eq {}} {
puts "Empty records"
exit 1 
} else {
puts "yMin is not empty: <$yMin>
}

yMin 不为空:<-6.14999999999999e-02>

最后,我尝试修剪映射正则表达式来删除任何空格和制表符,但它们都不起作用。

set trim_yMin [string trim $yMin]
puts "trim_yMin: <$trim_yMin>"
set map_yMin [string map {" " ""} $yMin]
puts "map_yMin: <$map_yMin>"
regsub -all {s} $yMin {} reg_yMin
puts "reg_yMin: <$reg_yMin>"
if {$trim_yMin eq {} || $map_yMin eq {} || $reg_yMin eq {}} {
puts "Empty records"
exit 1
} else {
puts "trim_yMin is not empty: <$reg_yMin>"
puts "map_yMin is not empty: <$reg_yMin>"
puts "reg_yMin is not empty: <$reg_yMin>"
}

trim_yMin:<-6.14999999999999e-02>
map_yMin:<-6.14999999999999e-02>
reg_yMin:<-6.1499999999999e-02>
trim_yMin不为空:<-6.149999999999999e-02>
map_yMin不为空:<-6.149999999999999e-02>
reg_yMin不为空:<-6.14999999999999e-02>

在这里,我只显示正则表达式的结果。其他人的结果是一样的。

set reg_Y2 [expr {0.5 * $reg_yMin}]
puts "0.5 * reg_yMin: $reg_Y2"

不能使用空字符串作为"*">
的操作数,同时执行"expr {0.5 * $reg_yMin}"从"set reg_Y2 [expr {0.5 * $reg_yMin}]">
中调用

你能帮帮我吗?我真的不知道我还能尝试什么。提前谢谢。


更新和回复

二文

puts $bbox;
set yMin [lindex [lindex $bbox 0] 1]
puts "yMin: <$yMin>"
{-4.599999999999999e-02 -6.149999999999999e-02} {8.0000000000000002e-02

6.149999999999999e-02}
yMin: <-6.14999999999999e-02>

set Y2 [expr {0.5 * $yMin}]
puts $Y2

不能使用空字符串作为"*">
的操作数,同时执行"expr {0.5 * $yMin}">
从"集合 Y2 [expr {0.5 * $yMin}]"中调用

贝纳贾

puts [tcl::unsupported::representation $yMin]

value 是一个引用计数为 4 的字符串,对象指针位于 0x44ed0910,内部表示形式 0x450d6120:(nil),字符串表示形式"-6.14999999999....">

肖恩来说,

puts [tcl::unsupported::representation $yMin]
puts [binary encode hex $yMin]
puts [tcl::unsupported::representation $yMin]
puts [string is double -strict $yMin]
puts [tcl::unsupported::representation $yMin]
value 是一个字符串,refcount 为 4,对象指针位于 0x44ed6030,内部表示形式 0x450de4b0:(nil),字符串表示形式"-6.1499999999..."2D362E31343939393939393939393939652d3032



value 是一个字节数组,引用计数为 4,对象指针位于 0x44ed6030,内部表示形式0x44ee0dc0:(nil),字符串表示形式"-6.1499999999...">
1




value 是一个引用计数为 4 的双精度值,对象指针位于 0x44ed6030,内部表示形式 0xbfaf7ced916872af:(nil),字符串表示形式"-6.1499999999...">

set Y2 [expr {0.5 * -6.149999999999999e-02}]
puts "Y2: $Y2"
set new_Y2 [expr {0.5*-6.149999999999999e-02}]
puts "new_Y2: $new_Y2"
Y2: -0.03074999999999996

new_Y2: -0.030749999999999996

谢尔特·布朗

错误消息已更改!也许它表明了什么?

puts [tcl::unsupported::representation $yMin]
set yMin " $yMin"
puts [tcl::unsupported::representation $yMin]
set Y2 [expr {0.5 * $yMin}]
puts $Y2
value 是一个字符串,引用计数为 4,对象指针位于 0x44ec28a0,内部表示形式 0x450be540:(nil),字符串表示形式"-6.1499999999...">

value 是一个引用计数为 2 的字符串,对象指针位于 0x446bbc70,内部表示形式0x44695fd0:(nil),字符串表示形式" -6.149999999..."在执行"expr {0.5 * $yMin}">
时不能使用非数字字符串作为"*">




的操作数invoked from within
"set Y2 [expr {0.5 * $yMin}]">

如果在字符串为双精度严格$yMin后将值更改为双精度后计算仍然失败,则取二进制编码十六进制$yMin的结果,将其转换回字符串(使用二进制解码十六进制)并在计算中使用它。

puts "Is yMin double? : [string is double -strict $yMin]"
set binary_yMin [binary encode hex $yMin]
set double_binary_yMin [binary decode hex $binary_yMin]
puts "yMin: $yMin"
puts "Binary of double yMin: $binary_yMin"
puts "Double binary double: $double_binary_yMin"
set Y2 [expr {0.5 * $double_binary_yMin}]
puts $Y2
yMin 是双倍吗? : 1 yMin: -6.14999999999999e-02 双二进制 yMin: 2d362e3134393939393939393939393939652d3032 双

二进制双精度: -6.14999999999999e-02不能使用空字符串作为"*"的操作数,同时执行"expr {0.5 * $double_binary_yMin}"从"set Y2


[expr {0.5 * $double_binary_yMin}]">

中调用

你从tcl::mathop::* 0.5 $yMin得到什么?

puts [tcl::mathop::* 0.5 $yMin]

不能使用空字符串作为"*">
的操作数,同时执行
"TCL::mathop::* 0.5 $yMin">
从内部
调用"放置 [tcl::mathop::* 0.5 $yMin]">


相关帖子

  1. 为什么Tcler建议支撑你的expr
  2. 什么意思 - 不能在 tcl- 上使用空字符串作为"*"的操作数? 如何解决
  3. 如何在 TCL 中去除字符串中的空格?
  4. 使用 TCL
    从文件中读取字符串后从字符串中删除空格
  5. TCL 脚本
    中缺少@处的操作数
  6. 确定 Tcl 中变量的类型

如果没有该bbox变量的确切起点,我们只能真正推测。该值应该有效:

% set yMin -6.149999999999999e-02
-6.149999999999999e-02
% expr {0.5 * $yMin}
-0.030749999999999996

如果输入数据是普通的旧假数据,并且空字符串永远不足以支持乘法,那么所有查看expr可能失败的方式都无济于事。(这不是Python!)我们必须备份几个步骤。

怀疑问题是bbox变量有时不是您期望的形状,有时具有这样的值:1.0 -6.149999999999999e-02 3.0 4.0.在这种情况下,[lindex [lindex $bbox 0] 1]将生成一个空字符串(因为由于语言的历史,从列表末尾索引会这样做):

% set bbox {1.0 -6.149999999999999e-02 3.0 4.0}
1.0 -6.149999999999999e-02 3.0 4.0
% puts >[lindex [lindex $bbox 0] 1]<
><

在这种情况下,仅使用lindex $bbox 1会更好。

% puts >[lindex $bbox 1]<
>-6.149999999999999e-02<

嵌套lindex有一个简写:

lindex $boox 0 1

但是边界框(至少当它们来自 Tk 时)通常只是四个数值的简单列表,X1Y1X2Y2因此在它们上使用嵌套形式很可能既错误又效率低下。

这只是这里的猜想:您指出坐标来自某个模糊的来源。也许开发人员创建了一个新的对象类型,但没有正确实现转换过程。打印值时,将使用字符串表示形式。但是当你尝试乘以这个值时,它想将神秘的对象类型转换为双精度值,这似乎无法正常工作。

您一直在尝试删除空格。但由于没有空格,因此不会修改该值。但是,如果您添加空格会发生什么?例如:set yMin " $yMin".这应该将变量转换为纯字符串(您可以使用tcl::unsupported::representation进行检查)。如果您随后尝试将其相乘,则将使用将字符串转换为双精度的常规 Tcl 转换过程。请注意,数字周围的空白对于expr是完全可以接受的,所以你应该能够乘以修改后的$yMin。

这不是答案,而是带有格式的评论

% set bbox {{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}}
{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}
% set yMin [lindex [lindex $bbox 0] 1]
-6.149999999999999e-02
% expr {1 + $yMin}
0.9385

代码中正在发生其他更改变量值的事情。查看如何创建最小、可重现的示例

相关内容

  • 没有找到相关文章