将CSV解析为键值对

时间:2018-06-13 23:56:57

标签: tcl

我有一个csv文件,其中包含主机名和附加的序列号。我想创建一个键值对,键为主机名,值为序列号列表。序列号可以是一个或多个。

例如:

A, 1, 2, 3, 4
B, 5, 6
C, 7, 8, 9
D, 10

我需要访问密钥A并获取{1 2 3 4}作为输出。如果我访问D,我应该{10}

我该怎么做?由于我使用的TCL版本不支持CSV等任何软件包,因此我也无法安装它,因为它在服务器中,所以我正在寻找一种不会解决问题的解决方案。包括任何包裹。

目前,我正在使用\n拆分该行,然后处理每个元素。然后我用","分割元素。然后我在列表中获取主机名和序列号。然后,我将列表的第0个索引用作主机名,将剩余值用作序列号。有更清洁的解决方案吗?

5 个答案:

答案 0 :(得分:0)

我会做类似的事情:

#!/usr/bin/env tclsh
package require csv
package require struct::queue

set filename "file.csv"
set fh [open $filename r]

set q [struct::queue]
csv::read2queue $fh $q
close $fh

set data [dict create]
while {[$q size] > 0} {
    set values [lassign [$q get] hostname]
    dict set data $hostname [lmap elem $values {string trimleft $elem}]
}

dict for {key value} $data {
    puts "$key => $value"
}

然后

$ tclsh csv.tcl
A => 1 2 3 4
B => 5 6
C => 7 8 9
D => 10

答案 1 :(得分:0)

这里给出的重复建议是使用CSV包来实现此目的。另请参阅@ glenn-jackman的答案。如果不可用,则在服务器端获取它的时间会更好。

然而,为了让您开始,您可能希望采用以下方式:

set dat {
    A, 1, 2, 3, 4
    B, 5, 6
    C, 7, 8, 9
    D, 10
}

set d [dict create]

foreach row [split [string trim $dat] \n] {
    set row [lassign [split $row ,] key]
    dict set d [string trim $key] [concat {*}$row]
}

dict get $d A
dict get $d D

但是,请注意,当您完全控制正在处理的数据及其表示时,这种手工编织的解决方案通常仅用于其目的。同样,通过获取CSV包可以更好地投入时间。

答案 2 :(得分:0)

我试过这种方式让它运转起来。再次感谢您的投入。是的,我知道csv包很简单,但我不能在服务器/产品中安装它。

set multihost "host_slno.csv"
set fh1 [open $multihost r]
set data [read -nonewline $fh1]
close $fh1
set hostslnodata [ split $data "\n" ]
set hostslno [dict create];

foreach line $hostslnodata {
  set line1 [join [split $line ", "] ]
  puts "$line1"
  if {[regexp {([A-Za-z0-9_\-]+)\s+(.*)} $line1 match hostname serial_numbers]} {
    dict lappend hostslno $hostname $serial_numbers
  }
}
puts [dict get $hostslno]

答案 3 :(得分:0)

csv包中的源代码可用。如果您无法安装完整的csv软件包,则可以在此处添加代码:

http://core.tcl.tk/tcllib/artifact/2898cd911697ecdb

如果您仍然不能使用该选项,则需要去除所有空白并在“,”上分割。

较早的答案的替代方法是使用字符串映射:

set row [split [string map  {" " ""} $row ] ,]

字符串映射将删除所有空格,然后在“,”上分割

将文本行转换为有效的tcl列表后:

A 1 2 3 4
B 5 6
C 7 8 9
D 10

然后,您可以使用lindex和lrange命令完成所有操作。

foreach row $data {
    set server [lindex $row 0]
    set serial_numbers [lrange $row 1 end]
    dict set ...

答案 4 :(得分:0)

一种可能性:

set hostslno [dict create]
set multihost "host_slno.csv"

set fh1 [open $multihost]
while {[gets $fh line] >= 0} {
    set numbers [lassign [regexp -inline -all {[^\s,]+} $line] hostname]
    dict set hostslno $hostname $numbers
}
close $fh1

puts [dict get $hostslno A]
相关问题