いざというときに備えるコード片、小物


リストからランダムに一つ選んで返す

ゲームなどでよく使います。

proc getRandomFlowerName listv {
    set index [expr int(rand() * [llength $listv])]
    set a [lindex $listv $index]
    return $a
}


リストをランダムにシャッフルする

Tclリストのシャッフルはなかなか面倒ですが、lsetコマンドを使うのが一般的なようです。

proc shuffle listv {
    set n [llength $listv]
    # 回数は適当
    for {set i 0} {$i < 1000} {incr i} {
        set n1 [expr int(rand()*$n)]
        set n2 [expr int(rand()*$n)]
        set temp [lindex $listv $n1]
        lset listv $n1 [lindex $listv $n2]
        lset listv $n2 $temp
    }
    return $listv
}


カレントディレクトリに存在するディレクトリだけを表示する

foreach e [glob -dir [pwd] -tails -types d *] { puts $e }

globコマンドは-dirオプションで起点ディレクトリを指定できますが、 それをすると戻る各エントリが絶対パスになってしまいます。 -tailsも一緒につけると、ファイル名だけのリストになって返ってきます。


ファイルを読み、各行が各要素であるようなリストを作る

proc readFileAsList fileName {
    set fin [open $fileName r]; set buf [read $fin]; close $fin
    return [split $buf "\n"]
}
foreach e [readFileAsList "data.txt"] { puts "<$e>" }

これはよくある処理で、作り方は様々ですが、 上の例は一度ファイルの内容を丸ごと読んでしまい、その後splitで分割しています。


固定長データファイルを読み、各行の一部の桁を16進表記で出力する

うわあ、コボリックスな処理ですねえ(意味わからん)

set fin [open "input.dat" r]; fconfigure $fin -translation binary -encoding binary
set fout [open "output.dat" w]; fconfigure $fout -translation binary -encoding binary
while {! [eof $fin]} {
    set buf [string range [read $fin 244] 58 97]
    binary scan $buf H* aaa
    puts $fout $aaa
}
close $fin; close $fout

中身の数字を適当に毎回書き換えて使います。 上の例は、1行が244バイト (注意:行末の改行文字を含む。改行文字はWindowsでは2バイト(CR+LF)、UNIXでは1バイト(LF)です) である固定長データファイル "input.dat" を読み、各行の59バイト目(注意:先頭が0なので-1します)から98バイト目までの40バイトを 16進表記に変換して別ファイルに出力します。 16進表記は1文字2バイトなので、 出力ファイルの各行の長さは(この例では)40×2=80バイトになります。

やねうらの top
(first uploaded 2007/03/21 last updated 2022/04/24, MISUMI URANO)