2017-10-18 3 views
0

私はこのようなアスキーテキストファイルを解析しようとしています。Tclでハイパーフォーマットされたテキストファイルの特定の枝を解析する

KEY1 VAL1 
    KEY2 VAL2 
    KEY3 VAL3 
     KEY4 VAL4 
    KEY5 VAL5 
    KEY6 VAL6 
     KEY7 VAL7 
KEY8 VAL8 
    KEY9 VAL9 

私はこれをキー1,5,7からの値のフラットテーブルに変換したいと思います。私はファイルをループして値を読み取るフラグを設定する非常に醜いbrute forceアルゴリズムを持っていますが、それは最も効率的ではありません。以下のような

何か:

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

答えて

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 

このコードは(lappendによって)、それが成長keylist、キーのリストを保持し、契約(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 

注:あなたが唯一のルートからの降下の単一の行に続くキーを使用する場合は、このコードを使用することができます。値が常にアトミックな場合、コードを少しだけ規則的にすることができます。

0

はここで辞書にそのデータを解析するためのいくつかのコードです:

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} 
関連する問題