我试图解析一个看起来像这样的ascii文本文件。
KEY1 VAL1
KEY2 VAL2
KEY3 VAL3
KEY4 VAL4
KEY5 VAL5
KEY6 VAL6
KEY7 VAL7
KEY8 VAL8
KEY9 VAL9
我想将此转换为KEYs 1,5,7的值的平面表。我有一个非常丑陋的强力算法循环文件并设置标志来读取值,但这并不是最有效的。
类似的东西:
set f [open $filename]
set data [split [read $f] "\n"]
foreach line $data {
if {[string match KEY1* $line] ==1} {set key1match 1}
if {($keymatch1==1) && ([string match KEY5* $line] ==1} {set key5match 1}
...
是否有更优雅的方式来生成此映射?
答案 0 :(得分:0)
这是你想要的吗?
set keylist {}
set keyset {KEY1 KEY5 KEY7}
set flatDict {}
foreach line [split [string trim $input] \n] {
if {[regexp {(\s*)(\w+)\s*(.*)} $line -> indent key val] && $key in $keyset} {
set level [expr {[string length $indent] / 2}]
set keylist [lrange $keylist 0 $level]
lappend keylist $key
dict set flatDict $keylist $val
}
}
% set flatDict
KEY1 VAL1 {KEY1 KEY5} VAL5 {KEY1 KEY5 KEY7} VAL7
此代码保留一个键列表keylist
,它根据缩进增长(通过lappend)和收缩(通过lrange)(并且完全取决于缩进是否正确)。仅考虑给定集合中的密钥keyset
。对于添加到字典中的每个值,当前$keylist
用作键(dict
命令可以处理键层次结构,但是键必须是独立的而不是在列表中(例如{{ 1}})。
文档: && (operator), / (operator), dict, expr, foreach, if, in (operator), lappend, lrange, regexp, set, split, string, Syntax of Tcl regular expressions
事后补充:通过选择密钥,实际上不需要签订密钥列表。如果您只使用从根单线下降的键,则可以使用以下代码:
dict set myDict foo bar 123
请注意,在这两个示例中,我提供了可能包含空格的值。如果值始终是原子的,则可以使代码更加规则。
答案 1 :(得分:0)
这里有一些代码可以将数据解析为字典:
MouseDown
输出
set indent_width 2
set d [dict create]
set fh [open [lindex $argv 0] r]
while {[gets $fh line] != -1} {
regexp {^(\s*)(\S+)\s*(.*)} $line -> indent key value
if {$key eq ""} continue
set level [expr {[string length $indent] / $indent_width}]
dict set d $key level $level
dict set d $key value $value
dict set d $key children [list]
dict set d $key parent ""
dict set d last $level $key
set prev_level [expr {$level - 1}]
if {$prev_level >= 0} {
set parent_key [dict get $d last $prev_level]
dict update d $parent_key item {
dict lappend item children $key
}
dict set d $key parent $parent_key
}
}
dict unset d last
dict for {key value} $d {puts [list $key $value]}