Что возвращает функция разделения Perl, когда между токенами нет значения? - PullRequest
4 голосов
/ 27 октября 2010

Я пытаюсь разделить строку, используя функцию разделения, но между токенами не всегда есть значение.

Пример: ABC, 123 ,,,,,, XYZ

Я не хочу пропустить несколько токенов. Эти значения находятся в определенных позициях в строке. Однако, когда я делю разделение, а затем пытаюсь выполнить пошаговый просмотр полученного массива, я получаю предупреждения «Использование неинициализированного значения».

Я попытался сравнить значение, используя $splitvalues[x] eq "", и я попытался использовать defined($splitvalues[x]), но я не могу понять, как определить, что функция split добавляет в мой массив, когда между токенами нет значения.

Вот фрагмент моего кода (теперь с большей хрусткостью):

my @matrixDetail = ();

#some other processing happens here that is based on matching data from the 
#@oldDetail array with the first field of the @matrixLine array. If it does
#match, then I do the split
if($IHaveAMatch)
{
    @matrixDetail = split(',', $matrixLine[1]);
}
else
{
    @matrixDetail = ('','','','','','','');
}

my $newDetailString =
  (($matrixDetail[0] eq '') ? $oldDetail[0] : $matrixDetail[0])
. (($matrixDetail[1] eq '') ? $oldDetail[1] : $matrixDetail[1]) 
    .
    .
    .
. (($matrixDetail[6] eq '') ? $oldDetail[6] : $matrixDetail[6]);

, поскольку это всего лишь фрагменты, я оставил часть другой логики, но оператор if находится внутри подпрограммы, которая технически возвращает массив @matrixDetail обратно. Если я не нахожу совпадение в своей матрице и вручную устанавливаю массив равным массиву пустых строк, то я не получаю предупреждений. Это только когда разделение заполняет @matrixDetail.

Кроме того, я должен отметить, что я пишу код в течение почти 15 лет, но только недавно мне понадобилось работать с Perl. Логика в моем сценарии здравая (или, по крайней мере, работает), я просто анализирую свои предупреждения и пытаюсь выяснить этот маленький нюанс.

Ответы [ 4 ]

4 голосов
/ 27 октября 2010
#!perl

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

my $str = "ABC,123,,,,,,XYZ";
my @elems = split ',', $str;
print Dumper \@elems;

Это дает:

$VAR1 = [
          'ABC',
          '123',
          '',
          '',
          '',
          '',
          '',
          'XYZ'
        ];

Вставляет пустую строку.

Edit: Обратите внимание, что документация для split() заявляет, что «по умолчанию пустые начальные поля сохраняются, а пустые завершающие поля удаляются».Таким образом, если ваша строка ABC,123,,,,,,XYZ,,,,, то ваш возвращенный список будет таким же, как в приведенном выше примере, но если ваша строка ,,,,ABC,123, то у вас будет список с тремя пустыми строками в элементах 0, 1 и 2 (в дополнение к 'ABC' и '123').

Edit 2: Попробуйте выгрузить массивы @matrixDetail и @oldDetail.Вполне вероятно, что один из них не такой длины, как вы думаете.Вы также можете проверить количество элементов в этих двух списках, прежде чем пытаться использовать их, чтобы убедиться, что у вас есть столько элементов, сколько вы ожидаете.

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

Я предлагаю использовать Text :: CSV из CPAN.Это готовое решение, которое уже охватывает все странные крайние случаи анализа файлов в формате CSV.

0 голосов
/ 27 октября 2010

Пустые поля в середине будут ''. Пустые поля в конце будут опущены, если вы не укажете третий параметр для разделения достаточно большой (или -1 для всех).

0 голосов
/ 27 октября 2010

с разделителями, между которыми ничего нет, при разбиении дают пустые строки.Пустые строки оцениваются как ложные в логическом контексте.

Если вы знаете, что ваш ввод "details" никогда не будет содержать "0" (или другой скаляр, который оценивается как false), это должно сработать:

my @matrixDetail = split(',', $matrixLine[1]);
die if @matrixDetail > @oldDetail;

my $newDetailString = "";
for my $i (0..$#oldDetail) {
    $newDetailString .= $matrixDetail[$i] || $oldDetail[$i]; # thanks canSpice
}
say $newDetailString;

(возможно, есть другие скаляры, кроме пустой строки и нуля, которые оцениваются как ложные, но я не могу назвать их по макушке).

TMTOWTDI:

$matrixDetail[$_] ||= $oldDetail[$_] for 0..$#oldDetail;
my $newDetailString = join("", @matrixDetail);

edit: циклы for теперь переходят от 0 к $#oldDetail вместо $#matrixDetail, поскольку завершающие символы ",,," не возвращаются функцией split.

edit2: если вы не можете быть уверены, что реальный ввод не будет оценен как ложный, вы всегда можете просто проверить длину ваших элементов разбиения.Это безопаснее, определенно, хотя, возможно, и менее элегантно ^ _ ^

...