Как с помощью Perl читать записи из файла с двумя возможными разделителями записей? - PullRequest
1 голос
/ 12 февраля 2010

Вот что я пытаюсь сделать:

Я хочу прочитать текстовый файл в массив строк. Я хочу, чтобы строка заканчивалась, когда файл читается определенным символом (в основном ; или |)

Например, следующий текст

Would you; please
hand me| my coat?

будет отложено так:

$string[0] = 'Would you;';
$string[1] = ' please hand me|';
$string[2] = ' my coat?';

Могу ли я получить некоторую помощь по этому поводу?

Ответы [ 5 ]

6 голосов
/ 12 февраля 2010

Это сделает это. Хитрость в использовании расщепления при сохранении токена, на который вы разбиваете, заключается в использовании соответствия обратного просмотра нулевой ширины: split(/(?<=[;|])/, ...).

Примечание: ответ mctylr (в настоящее время самый высокий рейтинг) на самом деле не верен - он будет разбивать поля на новых строках, т.к. он работает только на одной строке файла за раз.

Ответ gbacon с использованием разделителя входных записей ($/) довольно умный - он экономит пространство и время - но я не думаю, что хотел бы видеть его в рабочем коде. Помещение одного разделенного токена в разделитель записей, а другого - в разделение, кажется мне немного неочевидным (вы должны бороться с этим с помощью Perl ...), что усложнит поддержку. Я также не уверен, почему он удаляет несколько новых строк (что, я думаю, вы не спрашивали?) И почему он делает это только для конца записей, заканчивающихся на «|».

# open file for reading, die with error message if it fails
open(my $fh, '<', 'data.txt') || die $!; 

# set file reading to slurp (whole file) mode (note that this affects all 
# file reads in this block)
local $/ = undef; 

my $string = <$fh>; 

# convert all newlines into spaces, not specified but as per example output
$string =~ s/\n/ /g; 

# split string on ; or |, using a zero-width lookback match (?<=) to preserve char
my (@strings) = split(/(?<=[;|])/, $string); 
3 голосов
/ 12 февраля 2010

Один из способов - ввести другой символ, например \n, всякий раз, когда ваш специальный символ найден, затем split на \n:

use warnings;
use strict;
use Data::Dumper;

while (<DATA>) {
    chomp;
    s/([;|])/$1\n/g;
    my @string = split /\n/;
    print Dumper(\@string);
}

__DATA__
Would you; please hand me| my coat?

Распечатывает:

$VAR1 = [
          'Would you;',
          ' please hand me|',
          ' my coat?'
        ];

ОБНОВЛЕНИЕ: исходный вопрос, заданный Джеймсом, отображал входной текст в одну строку, как показано в __DATA__ выше. Поскольку вопрос был плохо отформатирован, другие отредактировали вопрос, разбив 1 строку на 2. Только Джеймс знает, была ли предназначена 1 или 2 строки.

1 голос
/ 12 февраля 2010

Я предпочитаю ответ @ toolic , потому что он очень легко обрабатывает несколько разделителей.

Однако, если вы хотите слишком усложнить вещи, вы всегда можете попробовать:

#!/usr/bin/perl

use strict; use warnings;

my @contents = ('');

while ( my $line = <DATA> ) {
    last unless $line =~ /\S/;
    $line =~ s{$/}{ };
    if ( $line =~ /^([^|;]+[|;])(.+)$/ ) {
        $contents[-1] .= $1;
        push @contents, $2;
    }
    else {
        $contents[-1] .= $1;
    }
}

print "[$_]\n" for @contents;

__DATA__
Would you; please
hand me| my coat?
0 голосов
/ 12 февраля 2010

Позвольте Perl сделать для вас половину работы, установив $/ (разделитель входных записей) на вертикальную черту, а затем извлеките разделенные точкой с запятой поля:

#!/usr/bin/perl

use warnings;
use strict;

my @string;

*ARGV = *DATA;

$/ = "|";
while (<>) {
  s/\n+$//;
  s/\n/ /g;
  push @string => $1 while s/^(.*;)//;
  push @string => $_;
}

for (my $i = 0; $i < @string; ++$i) {
  print "\$string[$i] = '$string[$i]';\n";
}

__DATA__
Would you; please
hand me| my coat?

Выход:

$string[0] = 'Would you;';
$string[1] = ' please hand me|';
$string[2] = ' my coat?';
0 голосов
/ 12 февраля 2010

Что-то вроде

$text = <INPUTFILE>;

@string = split(/[;!]/, $text);

должен сделать трюк более или менее.

Редактировать: Я изменил "/;! /" На "/[;!]/".

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