Python中的类似Excel的文本导入:自动解析定宽列
在Excel中,如果你导入的是用空格分隔的文本,这些文本的列可能对不上,或者有些数据可能缺失,比如:
pH pKa/Em n(slope) 1000*chi2 vdw0
CYS-I0014_ >14.0 0.00
LYS+I0013_ 11.827 0.781 0.440 0.18
你可以选择将其当作固定宽度的列来处理,Excel会自动计算出每一列的宽度,通常效果还不错。那么在Python中有没有类似的库,可以自动处理格式不太好的固定宽度文本呢?
编辑:这是在Excel中导入固定宽度文本的样子。在第一步,你只需要勾选“固定宽度”的选项,然后在第二步,Excel已经自动添加了列的分隔线。只有在每一行的每个列分隔线之间没有至少一个空格重叠时,它才会处理得不太好。
1 个回答
首先,Excel(2003版,在家用的)并不是特别聪明。如果你的第1000列数据是1000 * chi2,中间有空格,Excel可能会猜错。
简单的情况是,如果你的数据最开始是用制表符(而不是空格)分开的,并且用多个制表符来表示空列,那么在TCL中很容易通过制表符来分割每一行,我想在Python中也是如此。
但我猜你的问题是他们只用了空格字符。解决这个问题的一个重要线索是把你的文本粘贴到记事本中,并选择一种固定大小的字体。这样一来,所有内容就会整齐对齐,你可以用每行的字符数来衡量“长度”。
所以,如果你可以依赖输入的这个特性,那么你可以用一种“筛选”的方法来自动识别列的分隔位置。在第一次处理每一行时,记录下那些被非空白字符占据的位置,如果某个位置曾经被非空白字符占据,就把它从你的列表中去掉。随着你处理,你会很快得到一组位置,这些位置从来没有被非空白字符占据。这样,这些位置就是你的列分隔符。在你的例子中,你的“筛选”结果会是位置10-16、23-24、32、42-47从来没有被非空白字符占据(假设我数得对)。
因此,这组位置的补集就是你的数据必须位于的列位置。对于每一行,每一块非空白字符将正好适合你上面识别出的那些列位置(即补集)。
我从来没有用过Python,所以附上一个TCL脚本,它会使用筛选的方法来识别文本中的列分隔位置,并生成一个新的文本文件,把那些空格字符替换成一个制表符——也就是说,10-16替换成一个制表符,23-24替换成另一个,等等。
生成的文件是用制表符分隔的,也就是简单的情况。我承认我只在你的小数据案例上试过,把它复制到一个叫ex.txt的文本文件中;输出会到ex_.txt。我怀疑如果标题中有空格,它也可能会有问题。
希望这能帮到你!
set fh [open ex.txt]
set contents [read $fh];#ok for small-to-medium files.
close $fh
#first pass
set occupied {}
set lines [split $contents \n];#split contents at line breaks.
foreach line $lines {
set chrs [split $line {}];#split each line into chars.
set pos 0
foreach chr $chrs {
if {$chr ne " "} {
lappend occupied $pos
}
incr pos
}
}
#drop out with long list of occupied "positions": sort to create
#our sieve.
set datacols [lsort -unique -integer $occupied]
puts "occupied: $datacols"
#identify column boundaries.
set colset {}
set start [lindex $datacols 0];#first occupied pos might be > 0??
foreach index $datacols {
if {$start < $index} {
set end $index;incr end -1
lappend colset [list $start $end]
puts "col break starts at $start, ends at $end";#some instro!
set start $index
}
incr start
}
#Now convert input file to trivial case output file, replacing
#sieved space chars with tab characters.
set tesloc [lreverse $colset];#reverse the column list!
set fh [open ex_.txt w]
foreach line $lines {
foreach ele $tesloc {
set line [string replace $line [lindex $ele 0] [lindex $ele 1] "\t" ]
}
puts "newline is $line"
puts $fh $line
}
close $fh