Excel-подобный импорт текста в Python: автоматический анализ столбцов фиксированной ширины - PullRequest
6 голосов
/ 14 июня 2011

В 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 библиотека, которая может так же автоматически разбивать плохо форматированный текст фиксированной ширины?

EDIT: Так выглядит импорт текста с фиксированной шириной в Excel. На первом этапе вы просто устанавливаете переключатель «фиксированной ширины», а затем на втором шаге Excel уже автоматически добавляет разрывы столбцов. Единственный раз, когда он не может сделать это должным образом, это когда по крайней мере один символ пробела не перекрывается в каждом разрыве столбца в каждой строке.

fixed width text importing in excel

1 Ответ

4 голосов
/ 15 июня 2011

Во-первых, Excel (2003, дома) не такой умный. Если ваш столбец 1000 * chi2 содержит пробелы, например, 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
...