2010-08-23 6 views
1

У меня есть строки такого родаКак я могу извлечь столбцы данных с помощью Perl?

NAME1    NAME2   DEPTNAME   POSITION 
JONH MILLER  ROBERT JIM  CS     ASST GENERAL MANAGER 

Я хочу выход быть name1 name2 и положение, как я могу это сделать с помощью разделения/регулярное выражение/дифферента/и т.д., и без использования модулей CPAN?

+9

Вы задали свой первый вопрос 20 дней назад и получили 4 ответа. За это время вы не голосовали ни за кого из них, вы не приняли ответа, и вы не уточнили свой вопрос, чтобы получить более качественные ответы, если ни один из них не был полезен для вас. Глядя на эту историю, можно сделать вывод, что вы не намерены вносить что-либо на этот сайт и просто принимать. –

+0

Жаль, что я не знал, что раньше я буду голосовать за них. Спасибо за то, что сказал мне. – Sunny

+0

@Paul - все еще 0 голосов :( – DVK

ответ

2

Если входные данные поступают в виде массива строк (@strings), это

for my $s (@strings) { 
    my $output = join ' ', 
       map /^\s*(.+)\s*$/ ? $1 :(), 
       unpack('A19 A15 x19 A*', $s); 
    print "$output\n" 
} 

бы извлечь и обрезать необходимую информацию.

NAME1 | NAME2 | ПОЛОЖЕНИЕ

и

JONH MILLER | РОБЕРТ ДЖИМ | ASST ГЕНЕРАЛЬНЫЙ ДИРЕКТОР

('|' были включены мной для лучшего expalnation результата)

С уважением

БВУ

+0

Unpack - отличный инструмент для этого, и мы рассмотрим почти этот же пример в _Effective Perl Programming_. Я бы хотел, чтобы в следующей книге была целая глава пакета. –

+0

@brian, «The Book» выглядит многообещающе, мне бы хотелось иметь главу о расширенных регулярных выражениях (например, как современная версия japhys Regex Arcana : http://japhy.perlmonk.org/articles/tpj/2004-summer.html). Кроме того, в первом издании старого «Advanced Perl Programming» (по Srinivasan) были некоторые интересные темы (Perl guts, embedding, XS-hands on и eval), которые были исключены из второго edt. (Саймон Козенс). Такие (более технические) расширенные темы не являются частью каких-либо реальных книг, которые я знаю. (Кстати: я заказал 2-й энд. E.P.P вчера). –

+0

Для кистей Perl получите _Extending и Embedding Perl_. Некоторые из интересных частей _Advanced Perl Programming, 1st Edition_ были основой для _Mastering Perl_. Для причудливого регулярного выражения _Mastering Regular Expressions_. _Mastering Perl_ также имеет некоторые причудливые регулярные выражения, а также _Effective Perl Programming_. Возможно, вам просто нужно прочитать больше книг. Помните, однако, что все эти вещи также находятся в документах, поэтому вам не нужно покупать книгу. –

6

Это зависит от того, являются ли эти поля фиксированной длиной или разделены ли вкладки. Самый простой (с использованием split) - это разделение вкладок.

my ($name1, $name2, $deptName, $position) = split("\t", $string); 

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

my ($name1, $name2, $deptName, $position) = unpack("A10 A10 A10 A10", $string); 
+0

Они не имеют фиксированной длины. – Sunny

+2

@ Сунни, тогда как вы собираетесь определить, где один поле заканчивается, а следующее начинается, видя, как некоторые из полей имеют в них пробелы. Либо вам нужно разграничить их с помощью определенного символа, как вкладка, либо вам нужно поместить их в определенные места. В первом случае вы используете split , во втором вы используете распаковку. –

+0

Спасибо, Пол. , когда я хочу проголосовать, говорит, что Vote Up требует 15 репутации. – Sunny

0

Чтобы разделить на пробельном:

@string_parts = split /\s{2,}/, $string; 

Это разделит $string на список подстрок. Сепаратором будет regex \s+, что означает один или несколько пробельных символов. Это включает пробелы, вкладки и (если я не ошибаюсь) новые строки.

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

+2

Это решение разделит строку как «JONH »,« MILLER », но это одно имя, поэтому это должен быть JONH MILLER, это означает, что решение не соответствует действительности. –

+1

@Nikhil: Good poi нт. Но вы можете сделать что-то вроде '@string_parts = split/\ s \ s + | \ t \ s * /, $ string' для разделения на несколько пробелов или одну вкладку и, возможно, другие пробелы. –

+0

@Platinum: Это правда, именно я делаю то же самое в своем ответе. –

0

Рассмотрите возможность использования AutoSplit в Perl однострочника из вашего командная строка:

$ perl -F/\s{2,}/ -ane 'print qq/@F[0,1,3]\n/' file 

Однострочный разделитель будет разделен на два или более последовательных пробела и pri nt первое, второе и четвертое поля, соответствующие полям NAME1, NAME2 и POSITION.

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

+0

Любая причина для нисходящего? – Zaid

1

Предполагая, что пространство между полями не фиксировано, так что разделите строку на основе двух или более пространств, чтобы он не разбивал имя, как JONH MILLER, на две части:.

#!/usr/bin/perl 
use strict; 
use warning; 
my $string = "NAME1    NAME2   DEPTNAME   POSITION 
      JONH MILLER  ROBERT JIM  CS     ASST GENERAL MANAGER "; 
my @string_parts = split /\s\s+/, $string; 
foreach my $test (@string_parts){ 
     print"$test\n"; 
} 
1

Из образца в нем содержится одно пространство, но двух или более смежных пространств нет. Таким образом, вы можете легко разделить на 2 или более пробелов. Единственное, что я могу добавить к этому, это использование

use List::MoreUtils qw<mesh>; 
my @names = map { chomp; $_ } split /\s{2,}/, <$file>; 
my @records = map { chomp; { mesh(@names, @{[ split /\s{2,}/ ]}) } } <$file>;