Функция Perl split () не обрабатывает символ трубы, сохраненный как переменную - PullRequest
2 голосов
/ 12 июля 2011

У меня небольшие проблемы со встроенной функцией разделения Perl. Я создаю сценарий, который редактирует первую строку файла CSV, который использует канал для разделения столбцов. Ниже первая строка:

KEY|H1|H2|H3

Однако, когда я запускаю скрипт, я получаю вывод:

Col1|Col2|Col3|Col4|Col5|Col6|Col7|Col8|Col9|Col10|Col11|Col12|Col13|

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

Для контекста, вот необходимая часть моего скрипта:

our $opt_h;
our $opt_f;
our $opt_d;

# Get user input - filename and delimiter
getopts("f:d:h");

if (defined($opt_h)) {
    &print_help;
    exit 0;
}

if (!defined($opt_f)) {
   $opt_f = &promptUser("Enter the Source file, for example /qa/data/testdata/prod.csv");
}

if (!defined($opt_d)) {
    $opt_d = "\|";
}

my $delimiter = "\|";
my $temp_file = $opt_f;
my @temp_file = split(/\./, $temp_file);
$temp_file = $temp_file[0]."_add-headers.".$temp_file[1];

open(source_file, "<", $opt_f) or die "Err opening $opt_f: $!";
open(temp_file, ">", $temp_file) or die "Error opening $temp_file: $!";

my $source_header = <source_file>;
my @source_header_columns = split(/${delimiter}/, $source_header);
chomp(@source_header_columns);

for (my $i=1; $i<=scalar(@source_header_columns); $i++) {
    print temp_file "Col$i";
    print temp_file "$delimiter";
}
print temp_file "\n";
while (my $line = <source_file>) {
    print temp_file "$line";
}

close(source_file);
close(temp_file);

Ответы [ 4 ]

6 голосов
/ 12 июля 2011

Первый аргумент split является скомпилированным регулярным выражением или шаблоном регулярного выражения. Если вы хотите разделить на текст |. Вам нужно будет передать шаблон , который соответствует |.

quotemeta создает шаблон из строки, соответствующей этой строке.

my $delimiter = '|';
my $delimiter_pat = quotemeta($delimiter);
split $delimiter_pat

В качестве альтернативы, quotemeta может быть доступен как \Q..\E внутри строк в двойных кавычках и т. П.

my $delimiter = '|';
split /\Q$delimiter\E/

\E можно даже опустить, если оно в конце.

my $delimiter = '|';
split /\Q$delimiter/

Я упоминал, что split также принимает скомпилированное регулярное выражение.

my $delimiter = '|';
my $delimiter_re = qr/\Q$delimiter/;
split $delimiter_re

Если вы не возражаете жестко закодировать регулярное выражение, это то же самое, что и

my $delimiter_re = qr/\|/;
split $delimiter_re
5 голосов
/ 12 июля 2011

Во-первых, | не является специальным внутри двойных кавычек. Если установить для $ delimiter значение "|", а затем убедиться в том, что он будет указан позже, сработает или, возможно, установка $ delimiter на "\\|" сама по себе будет приемлема.

Во-вторых, | является специальным внутри регулярного выражения, поэтому вы хотите процитировать его там. Самый безопасный способ сделать это - попросить Perl процитировать ваш код для вас. Используйте конструкцию \Q...\E в регулярном выражении, чтобы выделить данные, которые вы хотите процитировать.

my @source_header_columns = split(/\Q${delimiter}\E/, $source_header);

см .: http://perldoc.perl.org/perlre.html

1 голос
/ 12 июля 2011

Кажется, что все, что вы хотите сделать, это подсчитать поля в заголовке и распечатать заголовок.Могу ли я предложить что-то немного более простое, чем использование split?

my $str="KEY|H1|H2|H3"; 
my $count=0; 
$str =~ s/\w+/"Col" . ++$count/eg; 
print "$str\n";

Работает с большинством любых разделителей (кроме буквенно-цифровых и подчеркиваний), оно также сохраняет количество полей в $count, на случай, если оно потребуется позже.

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

my $d = shift || '[^|]';
if ( $d !~ /^\[/ ) {
    $d = '[^' . $d . ']';
}
my $str="KEY|H1|H2|H3"; 
my $count=0; 
$str =~ s/$d+/"Col" . ++$count/eg; 
print "$str\n";

Используя скобки, вам не нужно беспокоиться о экранировании метасимволов.

0 голосов
/ 12 июля 2011
#!/usr/bin/perl
use Data::Dumper;
use strict;
my $delimeter="\\|";
my $string="A|B|C|DD|E";
my @arr=split(/$delimeter/,$string);
print Dumper(@arr)."\n";

вывод:

$VAR1 = 'A';
$VAR2 = 'B';
$VAR3 = 'C';
$VAR4 = 'DD';
$VAR5 = 'E';

кажется, вам нужно определить делимер как \\ |

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