perl text :: csv - фильтрация определенных столбцов в документе csv и удаление других - PullRequest
2 голосов
/ 26 октября 2010

Я хотел бы отфильтровать определенные столбцы с помощью регулярного выражения и отбросить другие. Например, если у меня были следующие имена столбцов:

дата mem_total cpu.usagemhz.average_0 cpu.usagemhz.average_1 cpu.usagemhz.average_2

Я хотел бы захватить только столбцы, которые начинаются с "cpu.usage.mhz.average"

Является ли их особая функция text :: csv, которая поможет мне быстро проверить имена столбцов?

Спасибо! JD

* Обновление **

Я попытался ответить на Jimtut, и это очень близко к тому, что я ищу. Еще раз спасибо всем!

Вот код из jimtut с одним небольшим изменением оператора print внизу. Я добавил print $ colCount, чтобы посмотреть, что происходит с данными;

use Text::CSV;

my $file = "foo.csv";
my $pattern = ".*In";
open(F, $file) or warn "Warning! Unable to open $file\n";

my $lineCount = 0;
my %desiredColumns;
while(<F>) {
  $lineCount++;
  my $csv = Text::CSV->new();
  my $status = $csv->parse($_); # should really check this!
  my @fields = $csv->fields();
  my $colCount = 0;

  if ($lineCount == 1) {
    # Let's look at the column headings.
    foreach my $field (@fields) {
      $colCount++;
      if ($field =~ m/$pattern/) {
        # This heading matches, save the column #.
        $desiredColumns{$colCount} = 1;
      }
    }
  }
  else {
    # Not the header row.  Parse the body of the file.
    foreach my $field (@fields) {
      $colCount++;
      if (exists $desiredColumns{$colCount}) {
        # This is one of the desired columns.
        # Do whatever you want to do with this column!
        print "$colCount\t$field\n";
      }
    }
  }
}
close(F);

Вот результаты

colCount |  $field

12      565
13      73
14      36
15      32
16      127
17      40
18      32
19      42
20      171
12      464
13      62
14      32
15      24
16      109
17      21
18      19
19      39
20      150
12      515
13      76
14      28
15      30
16      119
17      15
18      25
19      46
20      169
12      500
13      71
14      30
15      28
16      111
17      20
18      18
19      40
20      167

Я хотел бы добавить эти данные в отдельные массивы или хэши. что ты думаешь? что-то вроде ...

foreach column { проверьте, существует ли уже хеш с таким номером столбца. Если нет, то создайте хеш. }

Затем просмотрите каждое поле и добавьте данные поля в соответствующий хеш.

Как вы думаете, это правильный путь для решения этой проблемы?

Ответы [ 3 ]

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

Нет, не конкретная функция в Text :: CSV. Я бы сделал что-то вроде этого:

use Text::CSV;

my $file = "foo.csv";
my $pattern = "cpu.usage.mhz.average.*";
open(F, $file) or die "Unable to open $file: $!\n";

my $lineCount = 0;
my %desiredColumns;
my %columnContents;

while(<F>) {
  $lineCount++;
  my $csv = Text::CSV->new();
  my $status = $csv->parse($_); # should really check this!
  my @fields = $csv->fields();
  my $colCount = 0;

  if ($lineCount == 1) {
    # Let's look at the column headings.
    foreach my $field (@fields) {
      $colCount++;
      if ($field =~ m/$pattern/) {
        # This heading matches, save the column #.
        $desiredColumns{$colCount} = 1;
      }
    }
  }
  else {
    # Not the header row.  Parse the body of the file.
    foreach my $field (@fields) {
      $colCount++;
      if (exists $desiredColumns{$colCount}) {
        # This is one of the desired columns.
        # Do whatever you want to do with this column!
        push(@{$columnContents{$colCount}}, $field);
      }
    }
  }
}
close(F);

foreach my $key (sort keys %columnContents) {
  print "Column $key: " . join(",", @{$columnContents{$key}}) . "\n\n";
}

Надеюсь, это поможет! Я уверен, что кто-то может написать это на одной строчке Perl, но это легче (для меня) читать ...

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

Поскольку интересующие вас поля имеют индекс 2-4, мы просто извлечем их из массива полей, возвращаемого getline (). Этот пример кода печатает их, но вы можете делать с ними что угодно.

use Text::CSV;                                     # load the module
my $csv = Text::CSV->new ();                       # instantiate
open $fh, "<somefile";                             # open the input
while ( my $fields = $csv->getline($fh) ) {        # read a line, and parse it into fields
    print "I got @{$fields}[2..4]\n";              # print the fields of interest
}
close ($fh)                                        # close when done
1 голос
/ 26 октября 2010

ПОЧЕМУ вы пытаетесь это сделать? Это минимизировать хранение? Устранить затраты на обработку для разбора многих ненужных столбцов?

Если последнее, вы не можете избежать этой стоимости обработки. Любое решение, которое вы придумали, ВСЕ ЕЩЕ прочитало бы и проанализировало 100% файла.

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

Кроме того, что именно вы имеете в виду "помочь мне быстро проверить имена столбцов?"? Если вы хотите получить имена столбцов, есть метод column_names(), если вы ранее установили имена столбцов с помощью column_names(getline($fh)).


Если вы хотите возвращать только определенные имена столбцов в хэше, чтобы избежать потери памяти на ненужных столбцах, для этого нет четкого API. Вы можете бросить свой собственный или использовать «ошибку / фичу» метода getline_hr():

  • Для первого (бросьте свой) вы можете сделать что-то вроде:

    my $headers = $csv->getline( $fh ); # First line is headers.
    my @headers_keep = map { /^cpu.usage.mhz.average/ ? 1 : 0 } @$headers;
    while ( my $row = $csv->getline( $fh ) ) {
        my $i = 0;
        my @row_new = grep { $headers_keep[$i++] } $@row;
        push @rows, \@row_new;
    }
    

    НО вы можете бросить свой ИЛИ.

  • Вы также можете использовать «функцию» из «getline_hr()», которая не присваивает значения хешу, если имя столбца является дубликатом (назначается только последняя версия) \

    В вашем случае, для имен столбцов: date,mem_total,cpu.usagemhz.average_0,cpu.usagemhz.average_1,cpu.usagemhz.average_2, просто установите массив column_names, чтобы он содержал значение "cpu.usagemhz.average_0" в первых 2 элементах массива - они НЕ будут затем сохранены getline_hr().

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

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