Как разделить строку, если некоторые поля содержат пробелы? - PullRequest
0 голосов
/ 21 октября 2010

У меня есть текстовый файл, который я извлек из файла PDF.Это организовано в табличном формате;это часть этого:

 DATE SESS PROF1 PROF2 COURSE SEC GRADE COUNT 

 2007/09 1 RODRIGUEZ TANIA DACSB 06500 001 A 3 

 2007/09 1 RODRIGUEZ TANIA DACSB 06500 001 A- 2 

 2007/09 1 RODRIGUEZ TANIA DACSB 06500 001 B 4 

 2007/09 1 RODRIGUEZ TANIA DACSB 06500 001 B+ 2 

 2007/09 1 RODRIGUEZ TANIA DACSB 06500 001 B- 1 

 2007/09 1 RODRIGUEZ TANIA DACSB 06500 001 WU 1 

 2007/09 1 NOOB ADRIENNE JOSH ROGER DBIOM 10000 125 C+ 1 

 2007/09 1 NOOB ADRIENNE JOSH ROGER DBIOM 10000 125 C+ 1 

 2007/09 1 FUENTES TANIA DACSB 06500 002 A 3 

 2007/09 1 FUENTES TANIA DACSB 06500 002 A- 8 

 2007/09 1 FUENTES ALEXA DACSB 06500 002 B 5 

 2007/09 1 FUENTES ALEXA DACSB 06500 002 B+ 3 

 2007/09 1 FUENTES ALEXA DACSB 06500 002 B- 1 

 2007/09 1 FUENTES ALEXA DACSB 06500 002 C 1 

 2007/09 1 FUENTES ALEXA DACSB 06500 002 C+ 1 

 2007/09 1 LIGGINS FREDER DACSB 06500 003 A 1

Где первая строка - это имена столбцов, а остальные строки - данные.Есть 8 столбцов, которые я хочу получить, поначалу это казалось очень простым делением на split(/\s+/, ...) для каждой прочитанной строки, но затем я заметил, что в некоторых строках есть дополнительные пробелы, например:

2007/09 1 NOOB ADRIENNE JOSH ROGER DBIOM 10000 125 C+ 1

Иногда данные для определенного столбца необязательны, как вы можете видеть.

Ответы [ 5 ]

2 голосов
/ 21 октября 2010

Верьте в это неоднозначно:

если PROF1 может содержать пробелы, как узнать, где он заканчивается и где начинается PROF2?Что если PROF2 также содержит пробел?Или 3 пробела ..

Вы, вероятно, даже не можете сказать себе, и если вы можете, это потому, что вы можете определить разницу между именем и фамилией.в Linux / Unix попробуйте запустить text2pdf в pdf .. может дать вам лучшие результаты.

2 голосов
/ 21 октября 2010

Проблема сложная, но не неразрешимая.Мне кажется, что курс всегда будет содержать пробел между альфа-кодом и числовым кодом, и что имена проф также всегда будут содержать пробел.Но тогда вы в значительной степени облажались, если у кого-то есть фамилия из двух частей, например "VAN DYKE".

Регулярное выражение описывает эту запись:

my $record_exp
    = qr{ ^ \s*
          (\d{4}/\d{2}) # yyyy/mm date
          \s+
          (\d+)         # any number of digits
          \s+
          (\S+ \s \S+) # non-space cluster, single space, non-space cluster
          \s+
          # sames as last, possibly not there, separating spaces are included
          # in the conditional, because we have to make sure it will start
          # right at the next rule.
          (?:(\S+ \s \S+)\s+)?  
          # a cluster of alpha, single space, cluster of digits
          (\p{Alpha}+ \s \d+)   
          \s+    # any number of spaces           
          (\S+)  # any number of non-space
          \s+    # ditto..  
          (\S+)  
          \s+    
          (\S+)  
        }x;

Что делает циклнамного проще:

while ( <$input> ) { 
    my @fields = m{$record_exp};
    # ... list of semantic actions here...
}

Но вы также можете хранить его в структурах, зная, что единственная переменная часть данных - это profs:

use strict;
use warnings;
my @records;
<$input>; # bleed the first line
while ( <$input> ) { 
    my @fields         = split; # split on white-space
    my $record         = { date => shift @fields };
    $record->{session} = shift @fields;
    $record->{profs}   = [ join( ' ', splice( @fields, 0, 2 )) ];
    while ( @fields > 5 ) { 
        push @{ $record->{profs} }, join( ' ', splice( @fields, 0, 2 ));
    }
    $record->{course} = splice( @fields, 0, 2 );
    @$record{ qw<sec grade count> } = @fields;
    push @records, $record;
}
1 голос
/ 21 октября 2010

Я бы, вероятно, все еще использовал бы split(), но затем получил бы доступ к данным таким образом:

my @values = split '\s+', $string;
my $date = $values[0];
my $sess = $values[1];
my $count = $values[-1];
my $grade = $values[-2];
my $sec = $values[-3];
my $course = $values[-4];
my @profs = @values[2..($#values-5)];

С этой конструкцией вам не нужно беспокоиться о том, сколько у вас профессий.Даже если у вас их нет, все остальные значения будут работать нормально (и вы получите пустой массив для своих специалистов).

1 голос
/ 21 октября 2010

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

1 голос
/ 21 октября 2010

Мне кажется, что первые четыре столбца и последние 5 столбцов присутствуют всегда, а 5-й и 6-й (prof2) столбцы являются необязательными.

Поэтому разделите строку, как вы пытались, выделите первые четыре ипоследние пять элементов из результирующего массива, затем все, что осталось, это ваш 5-й и 6-й столбцы

Если, однако, запись prof1 или prof2 может отсутствовать, вы застряли - ваш формат файла неоднозначный

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...