2011-09-15 34 views
7

Tôi đang tìm cách tìm loại biến trong TCL. Ví dụ: nếu tôi có biến $ a và tôi muốn biết thời tiết là biến số nguyên.Xác định loại biến trong TCL

tôi đã được sử dụng như sau cho đến nay:

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

và điều này dường như làm việc tuyệt vời cho các loại sau: alnum, alpha, ascii, boolean, kiểm soát, chữ số, đôi, sai sự thật, đồ thị, số nguyên, chữ viết thường, chữ in, dấu chấm, dấu cách, chữ số, chữ số, chữ số

Tuy nhiên, nó không thể cho tôi biết biến của tôi có thể là mảng, danh sách hoặc từ điển hay không. Có ai biết một cách để nói nếu một biến là một trong ba?

Cảm ơn trước

+0

bạn cần phiên bản TCL nào? –

+3

Bạn có thể giải thích tại sao bạn cần điều này ngay từ đầu? Ý tôi là, vì Tcl về cơ bản là một ngôn ngữ không cần thiết, những gì bạn yêu cầu trông giống như yêu cầu các rắc rối. – kostix

+0

@Kostix, tắt khóa học. Lý do tôi cần điều này là tạo ra một thủ tục trong đó một từ điển được phân tích cú pháp thành JSON. Các chuỗi ví dụ trong JSON được bao quanh bởi "" trong khi các số nguyên thì không. Ngoài ra, nếu từ điển chứa một từ điển khác, từ điển đó sẽ nhận đối tượng JSON của riêng nó trong đối tượng JSON. – Tom

Trả lời

0

Đối với mảng bạn muốn array exists cho dicts bạn muốn dict exists

cho một danh sách Tôi không nghĩ rằng có một xây dựng theo cách trước 8,5 ?, có này là từ http://wiki.tcl.tk/440

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

Cảm ơn bạn :) bạn có thể giải thích làm thế nào bạn sẽ sử dụng dict tồn tại trong trường hợp này? Tôi đã cố gắng sử dụng nó như thế này: nếu {[dict tồn tại $ nullData2 nullval]} { #do something } nhưng nó sẽ trả về lỗi nếu biến không phải là một dict. – Tom

+1

@Tom, trong trường hợp đó, tôi sẽ bao gồm câu lệnh if của bạn trong phần 'catch', điều này sẽ cho phép bạn xử lý trường hợp biến không phải là một dict. – TrojanName

11

biến Tcl của không có các loại (trừ hay không mà họ đang thực sự là một mảng kết hợp của các biến - tức là, bằng cách sử dụng cú pháp $foo(bar) - fo r mà bạn sử dụng array exists) nhưng giá trị của Tcl làm. Vâng, phần nào. Tcl có thể thay đổi giá trị giữa các loại khác nhau khi nó thấy phù hợp và không hiển thị thông tin này [*]; tất cả những gì bạn thực sự có thể làm là kiểm tra xem một giá trị có phù hợp với một loại cụ thể hay không.

kiểm tra sự phù hợp như vậy được thực hiện với string is (nơi bạn cần lựa chọn -strict, vì những lý do lịch sử xấu xí):

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])" 
    } 
} 

Lưu ý rằng tất cả các giá trị phù hợp với các loại dây; Giá trị của Tcl là luôn luôn có thể tuần tự hóa.

[EDIT từ bình luận]: Đối với serialization JSON, có thể sử dụng hacks bẩn để tạo ra tuần tự "đúng" (nghiêm chỉnh, đặt tất cả mọi thứ trong chuỗi sẽ đúng từ quan điểm của Tcl nhưng điều đó không hữu ích cho các ngôn ngữ khác) với Tcl 8.6. Các mã để làm điều này, ban đầu được đăng trên Rosetta Code là:

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\"" 
} 

Cảnh báo: Đoạn mã trên là không được hỗ trợ. Nó phụ thuộc vào hacks bẩn. Nó có thể phá vỡ mà không cần cảnh báo. (Nhưng nó không làm việc. Porting để Tcl 8,5 sẽ đòi hỏi một phần mở rộng C nhỏ để đọc ra các chú thích loại.)


[*] đúng ra, nó cung cấp một giao diện hỗ trợ để phát hiện các loại chú thích hiện nay có giá trị bằng 8,6 - như một phần của ::tcl::unsupported::representation - nhưng thông tin đó ở dạng có chủ ý có thể đọc được và có thể thay đổi mà không cần thông báo. Đó là để gỡ lỗi, không phải mã. Ngoài ra, Tcl sử dụng khá nhiều loại khác nhau trong nội bộ (ví dụ:, lệnh được lưu trong bộ nhớ cache và tên biến) mà bạn sẽ không muốn thăm dò trong các trường hợp bình thường; điều này là khá phức tạp dưới mui xe ...

+0

Cảm ơn bạn đã phản hồi, nhưng có vẻ như điều này sẽ không hoạt động. Trong if {[string is list $ foo]} {section. Các chuỗi chứa nhiều từ cũng được xem danh sách als.Ngoài ra, nếu tôi có danh sách chứa số lượng mặt hàng, mã này sẽ luôn phân loại nó làm từ điển. Tôi không chắc chắn nếu những gì tôi đang cố gắng làm là thậm chí có thể mặc dù, mã của bạn cũng có thể là sollution tốt nhất có thể. – Tom

+1

@Tom, đó là vì một chuỗi có nhiều từ không được phân biệt với một biến được tạo bằng lệnh 'danh sách'. Ví dụ: hãy thử điều này: đặt foo "ab bb dd"; lindex $ foo 1 – TrojanName

+0

là 'chuỗi là danh sách' 8.5 hoặc 8.6 ?, theo như tôi thấy, nó có thể không có sẵn cho Tom? –

0

Để xác định xem một biến là một mảng:

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

Bạn đang thiếu '[mảng tồn tại varname]' - http://www.tcl.tk/man/tcl8.5/TclCmd/array.htm –

+0

jk đã đề cập mảng tồn tại, tôi chỉ muốn cung cấp một cách khác để làm việc. –

+1

Tôi hiểu. Việc tạo danh sách các tên mảng (chỉ cần vứt chúng đi) là tốn kém: bạn có thể muốn 'mảng kích thước' thay thế. –

1

Nếu bạn muốn để đối phó với JSON sau đó tôi đánh giá cao đề nghị bạn đọc trang JSON trên wiki Tcl: http://wiki.tcl.tk/json .

Trên trang đó, tôi đã đăng một hàm đơn giản để biên dịch các giá trị Tcl thành chuỗi JSON được cung cấp một bộ mô tả định dạng. Tôi cũng tìm thấy các cuộc thảo luận trên trang đó rất nhiều thông tin.

3

Các câu trả lời khác đều cung cấp thông tin rất hữu ích, nhưng đáng chú ý là có rất nhiều người dường như không bị lúng túng lúc đầu.

Trong Tcl, giá trị không có loại ... câu hỏi là liệu chúng có thể được sử dụng như một loại nhất định hay không. Bạn có thể nghĩ về nó theo cách này

string is integer $a 

Bạn đang không yêu cầu

Là giá trị trong $ a là một số nguyên

gì bạn đang yêu cầu là

Tôi có thể sử dụng giá trị bằng $ a làm số nguyên

Tính hữu ích của nó để xem xét sự khác biệt giữa hai câu hỏi khi bạn đang suy nghĩ dọc theo dòng "là số nguyên này". Mỗi số nguyên cũng là một danh sách hợp lệ (của một phần tử) ... do đó, can be used là một trong hai và cả hai lệnh string is sẽ trả về true (như một số khác cho một số nguyên).

Các vấn đề liên quan