Как прочитать файл и сделать записи для каждой строки - PullRequest
1 голос
/ 07 декабря 2010

Нужна помощь в написании Perl-программы, которая принимает входной файл и выполняет манипуляции на основе последующих команд.Я начинающий студент Perl, поэтому, пожалуйста, не забывайте о предложениях.Структура, которую я имею до сих пор, является основной программой и 4 подпрограммами.

У меня проблемы с двумя частями:

  1. Запись части основного сегмента, которая создает уникальную запись для каждой строки из входного файла (который является фиксированной шириной формата).Я думаю, что это должно быть сделано с substr, но я не знаю, как это должно быть структурировано.Распаковка пока выходит за рамки моего изучения.

  2. Одна из функций, вызываемых в основной программе, - это подпрограмма «расстояние», которая будет вычислять расстояние между атомами.Я думаю, что это должен быть цикл For внутри цикла For.Любые мысли о том, какой подход я должен использовать?

Записи должны хранить массив записей атомов (одна запись / атом на новую строку):

•Серийный номер атома, 5 цифр.(столбцы 7 - 11)

• Трехбуквенное название аминокислоты, к которой она принадлежит (столбцы 18 - 20)

• Действительное число трех атомов в виде десятичных и ортогональных координат(x, y, z) (столбцы 31 - 54)
Для X в ангстремах столбцы.31-38
Для Y в ангстремах cols.39-46
Для Z в ангстремах cols.47-54

• Одно- или двухбуквенное имя элемента атома (например, C, O, N, Na) (столбцы 77-78)

sub Distance # принять массив атомовзаписывает и возвращает максимальное расстояние
# между всеми парами атомов в этом массиве.(столбцы 31-54)

Вот пример текста из входного файла.

# truncating for testing purposes. Actual data is aprox. 100 columns     
# and starts with ATOM or HETATM    
__DATA__   
ATOM   4743  CG  GLN A 704      19.896  32.017  54.717  1.00 66.44           C    
ATOM   4744  CD  GLN A 704      19.589  30.757  55.525  1.00 73.28           C    
ATOM   4745  OE1 GLN A 704      18.801  29.892  55.098  1.00 75.91           O  

Вот что у меня есть для основного и вспомогательного для создания записей.Я ненавижу быть хромым, но мне пока что нечего показывать для подпункта «Расстояние», поэтому не беспокойтесь о предоставлении кода, любые предложения о том, как подойти, будут очень благодарны.

use warnings;
use strict; 

my @fields;
my @recs;

while ( <DATA> ) {
chomp;
@fields = split(/\s+/);
push @recs, makeRecord(@fields);
}

for (my $i = 0; $i < @recs; $i++) {
printRec( $recs[$i] );
}
my %command_table = (
  freq => \&freq,
  length => \&length,
  density => \&density,
  help => \&help, 
  quit => \&quit
);

print "Enter a command: ";
  while ( <STDIN> ) {
  chomp; 
  my @line = split( /\s+/);
  my $command = shift @line;
  if ($command !~ /^freq$|^density$|length|^help$|^quit$/ ) {
    print "Command must be: freq, length, density or quit\n";
  }
    else {
    $command_table{$command}->();
  }
print "Enter a command: ";
}

sub makeRecord 
# Read the entire line and make records from the lines that contain the 
# word ATOM or HETATM in the first column. Not sure how to do this:
{
 my %record = 
 (
 serialnumber => shift,
 aminoacid => shift,
 coordinates => shift,
 element  => [ @_ ]
 );
 return\%record;
 }

Ответы [ 3 ]

1 голос
/ 07 декабря 2010

Странно, что unpack выходит за рамки, когда я вижу использование таблицы отправки. Было бы глупо игнорировать использование unpack, если обрабатываются файлы фиксированного формата. В приведенном ниже коде нет ничего «продвинутого»:

use strict;
use warnings;
use Data::Dump 'dump';   # Use this if you want 'dump' function to work

my @records;
while ( my $record = <DATA> ) {

    next unless $record =~ /^ATOM|^HETATM/;  # Skip unwanted records

    # unpack minimizes the amount of work the code has to do ...
    # ... especially since you only want a small part of the file
    # 'x' tokens are ignored, 'A' tokens are read ...
    # The number following each token represents repetition count ...
    # ... so in this case the first 6 characters are ignored ...
    # ... and the next 5 are assigned to $serNo

    my ( $serNo, $aminoAcid, $xCoord, $yCoord, $zCoord )
        = unpack 'x6A5x6A3x10A10A10A10', $record;        # Get only what you want

    # Assign data to a hash reference

    my $recordStructure = {
                            serialnumber => $serNo,
                            aminoacid    => $aminoAcid,
                            coordinates  => [ $xCoord, $yCoord, $zCoord ],
                          };

    push @records, $recordStructure;  # Append current record
}

# 'dump' is really useful to view data structures. No need for PrintRec!!

dump @records;
1 голос
/ 07 декабря 2010

В сети доступен Perl-код для работы с файлами PDB (что, очевидно, вы делаете).Я не предлагаю просто использовать модуль, который вы скачали, и покончить с этим, так как ваш инструктор наверняка не одобрит это, и вы не узнаете так много;) Но вы могли бы взглянуть на часть предлагаемого кода ипопытайтесь выяснить, решают ли какие-то биты вашу проблему.

Я немного погуглил, обнаружил, что есть ParsePDB.pm (например).Вы можете найти веб-страницу здесь .Я не смотрел на код или функциональность, хотя, я просто надеюсь, что там будет что-то, что вы можете найти полезным.

РЕДАКТИРОВАТЬ 1

Хорошо, сейчас 14 часов, и у меня возникло желание заняться кодированием, так как вы еще не приняли ответ, я подумал, что могу просто проигнорировать мой собственный совет и составить что-нибудь (как вы заметите, я скопировал данные Заида).структура) ...

#!/usr/bin/perl

use warnings;
use strict;

sub makeRecord {
   my ($ser_num, $aa, $x, $y, $z, $element) = @_;
   # copying Zaid now as her/his structure looks very sensible!
   my $record = {
                  serial  => $ser_num,
                  aa      => $aa,
                  element => $element,
                  xyz     => [$x, $y, $z],
                };
   return $record;
}


my $file = shift @ARGV;
my @records; # will be an array of hash references

open FILE, "<$file" or die "$!";
while (<FILE>) {
   if (/^ATOM|^HETATM/) { # only get the structure data lines
      chomp; # not necessary here, but good practice I'd say

      my @fields = split; # by default 'split' splits on whitespace

      # now use an array slice to only pass the array elements
      # you're interested in (using the positional indices from @fields):
      push @records, makeRecord(@fields[1,3,6,7,8,11]);
   }
}
close FILE;

РЕДАКТИРОВАТЬ 2

Относительно процедуры расстояния: цикл for внутри цикла for должен выполнять свою работу, но это грубая ошибкаПринудительный путь, который может занять довольно много времени (как вы должны будете сделать (number_of_atoms) ^ 2 вычисления), в зависимости от размера вашей входной молекулы.Для цели вашего задания подход грубой силы, вероятно, приемлем;в других случаях вам придется решить, следует ли отдавать предпочтение простоте кодирования или скорости вычислений.Если ваш инструктор также хочет, чтобы вы помнили о последнем, вы можете взглянуть на эту страницу (я знаю, что вы действительно хотите наибольшее расстояние, и вы находитесь в 3D, а не в 2D ...)

Хорошо, теперь я просто надеюсь, что вам удалось найти здесь несколько полезных фрагментов:)

1 голос
/ 07 декабря 2010

Ваши записи имеют формат фиксированной ширины, поэтому используйте unpack, чтобы разбить каждую запись на интересующие вас поля.Используйте указанные позиции столбцов каждого поля для создания шаблона для использования с unpack.

my @field_specs = (
    {begin =>  7, end => 11, name => 'serialnumber'},
    {begin => 18, end => 20, name => 'aminoacid'},
    {begin => 31, end => 38, name => 'X'}, 
    {begin => 39, end => 46, name => 'Y'},
    {begin => 47, end => 54, name => 'Z'}, 
    {begin => 77, end => 78, name => 'element'},
);
my $unpack_template;    
my @col_names;
for my $spec (@field_specs) {
    my $offset = $spec->{begin} - 1;
    my $width  = $spec->{end} - $offset;
    $template .= "\@${offset}A$width";
    push @col_names, $spec->{name};
}
print "Ready to read @col_names\n using template $template ...\n";

# prints 
# Ready to read serialnumber aminoacid X Y Z element 
#  using template @6A5@17A3@30A8@38A8@46A8@76A2 ...

my @recs;
while ( <DATA> ) {                
    my %record;
    @record{@col_names} = unpack($unpack_template, $_);    
    push @recs, \%record;                
}        
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...