2011-09-15 28 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(如其他幾個整數)。