2011-09-15 97 views
7

我正在寻找一种方法来查找TCL中变量的类型。例如,如果我有变量$ a并且我想知道它是一个整数。确定TCL中变量的类型

我一直使用至今如下:

if {[string is boolean $a]} { 
    #do something 
    } 

,这似乎工作非常适合以下几种类型: alnum,alpha或ASCII,布尔值,控制,数字,双,假的,图,然而,它不能告诉我,如果我的变量可能是一个数组,一个列表或一个字典,它不能告诉我。有谁知道一种方法来判断变量是否是这三种变量之一?

在此先感谢

+0

你需要什么版本的TCL? –

+3

你能解释一下为什么你需要这个吗?我的意思是,因为Tcl本质上是一种无类型的语言,所以你问的问题看起来像是在寻求麻烦。 – kostix

+0

@Kostix,当然。我需要的原因是创建一个将字典解析为JSON的过程。例如在JSON中的字符串被“”包围,而整数不是。另外,如果字典要包含另一个字典,那么该字典应该在JSON对象中获得它自己的JSON对象。 – Tom

回答

0

对于要array exists 为http://stardict.sourceforge.net/Dictionaries.php下载你想要dict exists

的名单,我不认为这是一个建于之前8.5的方式?还有这从http://wiki.tcl.tk/440阵列

proc isalist {string} { 
    return [expr {0 == [catch {llength $string}]}] 
} 
+0

谢谢你:)你能解释你将如何使用字典存在在这种情况下?我曾尝试使用它: if {[dict exists $ testData2 nullval]} { #do } 但如果变量不是字典,它将返回错误。 – Tom

+1

@Tom,在这种情况下,我会将你的if语句包装在'catch'中,这将允许你处理变量不是字典的情况。 – TrojanName

11

Tcl的变量没有类型(除了他们是否真的变量的关联数组 - 即使用$foo(bar)语法 - FO r你使用array exists)但Tcl的值。好吧,有点。 Tcl可以在不同类型之间进行变异,因为它认为合适,并且不公开这些信息[*];你所能做的就是检查一个值是否符合特定的类型。

这种一致性检查与完成string is(在您需要的-strict选项,丑陋的历史原因):

if {[string is integer -strict $foo]} { 
    puts "$foo is an integer!" 
} 

if {[string is list $foo]} { # Only [string is] where -strict has no effect 
    puts "$foo is a list! (length: [llength $foo])" 
    if {[llength $foo]&1 == 0} { 
     # All dictionaries conform to lists with even length 
     puts "$foo is a dictionary! (entries: [dict size $foo])" 
    } 
} 

请注意,所有值符合字符串类型; Tcl的值是总是可序列化。对于JSON序列化,可以使用肮脏的黑客来产生一个“正确的”序列化(严格地说,从Tcl的角度来看,所有东西都是正确的,但这对其他语言并不完全有帮助)与Tcl 8.6。代码要做到这一点,原本张贴在Rosetta Code是:

package require Tcl 8.6 

proc tcl2json value { 
    # Guess the type of the value; deep *UNSUPPORTED* magic! 
    regexp {^value is a (.*?) with a refcount} \ 
     [::tcl::unsupported::representation $value] -> type 

    switch $type { 
     string { 
      # Skip to the mapping code at the bottom 
     } 
     dict { 
      set result "{" 
      set pfx "" 
      dict for {k v} $value { 
       append result $pfx [tcl2json $k] ": " [tcl2json $v] 
       set pfx ", " 
      } 
      return [append result "}"] 
     } 
     list { 
      set result "\[" 
      set pfx "" 
      foreach v $value { 
       append result $pfx [tcl2json $v] 
       set pfx ", " 
      } 
      return [append result "\]"] 
     } 
     int - double { 
      return [expr {$value}] 
     } 
     booleanString { 
      return [expr {$value ? "true" : "false"}] 
     } 
     default { 
      # Some other type; do some guessing... 
      if {$value eq "null"} { 
       # Tcl has *no* null value at all; empty strings are semantically 
       # different and absent variables aren't values. So cheat! 
       return $value 
      } elseif {[string is integer -strict $value]} { 
       return [expr {$value}] 
      } elseif {[string is double -strict $value]} { 
       return [expr {$value}] 
      } elseif {[string is boolean -strict $value]} { 
       return [expr {$value ? "true" : "false"}] 
      } 
     } 
    } 

    # For simplicity, all "bad" characters are mapped to \u... substitutions 
    set mapped [subst -novariables [regsub -all {[][\u0000-\u001f\\""]} \ 
     $value {[format "\\\\u%04x" [scan {& } %c]]}]] 
    return "\"$mapped\"" 
} 

警告:不支持上面的代码。这取决于肮脏的黑客。它很容易在没有预警的情况下突破。 (但是它工作。移植到Tcl的8.5将需要一个微小的C扩展到读出的类型的注释。)


[*]严格,但它用于发现当前类型注释提供一个不支持的接口的价值为8.6 - 作为::tcl::unsupported::representation的一部分 - 但该信息采用刻意的人类可读形式,如有更改,恕不另行通知。它用于调试,而不是代码。而且,Tcl在内部使用相当多的不同类型(例如,,缓存的命令和变量名称),在正常情况下你不想探测;事情是引擎盖下相当复杂的...

+0

感谢您的反馈,但它似乎不会工作。在if {[string is list $ foo]} {部分。包含多个单词的字符串也被视为als列表。此外,如果我要有一个包含偶数项目的列表,这段代码总是会将它分类为字典。 我不确定如果我试图做甚至可能,但是,您的代码可能是最好的可能的溶剂。 – Tom

+1

@Tom,这是因为一个包含多个单词的字符串与用'list'命令创建的变量没有区别。例如,试试这个:set foo“ab bb dd”; lindex $ foo 1 – TrojanName

+0

is'string is list' 8.5 or 8.6 ?,据我所知,它可能无法提供给汤姆? –

0

如果要判断一个变量是一个数组:

proc is_array {var} { 
    upvar 1 $var value 
    if {[catch {array names $value} errmsg]} { return 1 } 
    return 0 
} 

# How to use it 
array set ar {} 
set x {1 2 3} 
puts "ar is array? [is_array ar]"; # ar is array? 1 
puts "x is array? [is_array x]"; # x is array? 0 
+0

你缺少'[array exists varname]' - http://www.tcl.tk/man/tcl8.5/TclCmd/array.htm –

+0

jk已经提到过数组存在,我只想提供一种不同的做事方式。 –

+1

我明白了。生成数组名称列表(只是为了抛弃它们)是昂贵的:您可能需要'array size'。 –

1

如果你要处理JSON那么我强烈建议你于Tcl维基阅读JSON页:http://wiki.tcl.tk/json

在那个页面上,我发布了一个简单的函数,它将Tcl值编译为给定格式描述符的JSON字符串。我还发现该页面上的讨论非常翔实。

3

其他答案都提供了非常有用的信息,但值得注意的是很多人起初似乎并不喜欢。

在Tcl中,值没有类型...他们的问题是它们是否可以用作给定的类型。你可以想想这样

string is integer $a 

你不问

是在$ a的值的整数

你所问的是

我可以使用$ a中的值作为整数吗

当你按照“这是一个整数”的思路来思考两个问题的区别时,它是有用的。每一个整数也是一个有效的列表(一个元素)...所以它can be used作为任何一个和两个string is命令将返回true(如其他几个整数)。