分析特定分公司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} 
... 

有没有产生这种映射更优雅的方式?

+1

你想看到什么输出?你能依靠每个子级缩进2个空格(或一致的数量)吗? –

+0

我想把它弄成一张平板或字典。缩进是基于层次结构的一致间隔 – Jonjilla

这是你想要的吗?

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)dictexprforeachifin (operator)lappendlrangeregexpsetsplitstringSyntax 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}