分析特定分公司hiearchically格式的文本文件中的Tcl
问题描述:
我试图解析ASCII文本文件看起来像这样。分析特定分公司hiearchically格式的文本文件中的Tcl
KEY1 VAL1
KEY2 VAL2
KEY3 VAL3
KEY4 VAL4
KEY5 VAL5
KEY6 VAL6
KEY7 VAL7
KEY8 VAL8
KEY9 VAL9
我想将其转换为来自键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}
...
有没有产生这种映射更优雅的方式?
答
这是你想要的吗?
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
命令可以处理密钥层次结构,但随后的键必须是分开的,而不是一个列表(例如dict set myDict foo bar 123
)内
文档: && (operator), / (operator), dict, expr, foreach, if, in (operator), lappend, lrange, regexp, set, split, string, Syntax of Tcl regular expressions
有感:用你的钥匙的实际选择,没有必要收缩密钥列表。如果你只使用遵循下降一行从根密钥,您可以使用此代码:
set keylist {}
set flatDict {}
foreach line [split [string trim $input] \n] {
set val [lassign [split [string trim $line]] key]
if {$key in $keyset} {
lappend keylist $key
dict set flatDict $keylist $val
}
}
% set flatDict
KEY1 VAL1 {KEY1 KEY5} VAL5 {KEY1 KEY5 KEY7} VAL7
注意,在这两个例子中,我已经提供了可能包含空白值。如果该值始终是原子的,则可以使代码更规整一些。
答
下面是一些代码到数据解析为一个字典:
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]}
输出
KEY1 {level 0 value VAL1 children {KEY2 KEY5} parent {}}
KEY2 {level 1 value VAL2 children KEY3 parent KEY1}
KEY3 {level 2 value VAL3 children KEY4 parent KEY2}
KEY4 {level 3 value VAL4 children {} parent KEY3}
KEY5 {level 1 value VAL5 children KEY6 parent KEY1}
KEY6 {level 2 value VAL6 children KEY7 parent KEY5}
KEY7 {level 3 value VAL7 children {} parent KEY6}
KEY8 {level 0 value VAL8 children KEY9 parent {}}
KEY9 {level 1 value VAL9 children {} parent KEY8}
你想看到什么输出?你能依靠每个子级缩进2个空格(或一致的数量)吗? –
我想把它弄成一张平板或字典。缩进是基于层次结构的一致间隔 – Jonjilla