Perl — получение значения из строки, разделенной запятыми

#perl

#perl

Вопрос:

У меня есть анализатор файлов perl, который я пытаюсь переписать. Это динамический анализатор, и мне нужно извлечь значение из строки, разделенной запятыми.

Строка, из которой я хочу получить одно значение, выглядит примерно так:

 ENTRYNAME-8,44544,99955,52,156,15:16:16,15:19:16
 

(Это единственная строка в каждом анализируемом файле, которая начинается с. ENTRYNAME- Все после - изменений для каждого анализируемого файла)

Я хочу значение после второй запятой. ( 99955 в примере выше)

Я попробовал следующее, но безуспешно:

 if (/ ENTRYNAME-((.*),(.*),(.*))/ ) 
{
    $entry_nr = $3;
    print "entry number = $entry_nr";
    next;
}
 

Комментарии:

1. Предпочтительно использовать Text::CSV или , по крайней мере, разделить линию на разделителе, split /,/

2. Будут ли эти строки csv когда-либо заключаться в кавычки и иметь встроенные ‘,’ в строке?

Ответ №1:

Проблема в том, что ваша первая строка захвата .* является жадной, поэтому она будет использовать всю вашу строку. Затем он вернется назад, чтобы найти две запятые и, как результат, совпадение с конца.

Также:

  • ( По какой-то странной причине вы сопоставляете литеральные круглые скобки. Поскольку у вас их нет, они никогда не будут совпадать.
  • Вам не нужно экранировать запятые ,
  • В вашем регулярном выражении не может быть случайного пробела / ENTRY... , если он не указан в целевой строке
  • Вам не нужно захватывать строки, которые вы не собираетесь использовать

Простое решение — использовать более строгую группу захвата (включая пункты выше):

 if (/ENTRYNAME-d ,d ,(d )/ ) 
 

Это приведет к захвату $1 .

Как указывает mpapec в комментарии, вы можете использовать Text::CSV для анализа данных CSV. Это будет намного безопаснее. Если ваши данные достаточно просты, это решение подойдет.

Комментарии:

1. Спасибо! Это, наконец, свело все воедино. Я бы использовал Text::CSV, но входные данные никоим образом не просты.

2. @user2837756 Вы, вероятно, должны использовать, только Text::CSV если у вас есть правильные данные csv. Регулярное выражение является жизнеспособным мелкомасштабным решением для ограниченного набора данных с ограниченными вариациями. Но вам, вероятно, следует добавить некоторые безопасные средства защиты и сообщения об ошибках на случай, если вы столкнетесь с неожиданными изменениями.

Ответ №2:

разделите его на массив и адресуйте напрямую:

 my @a = split /,/, $_;
print $a[2];
 

что здесь происходит, так это то, что все, что находится в $_ (обычно из for (@allmylines) { цикла), будет разделяться при каждом появлении , , помещая их все в array ( @a ) и удаляя , . затем вы можете обращаться к полям в массивах, начиная с 0 для первого поля. таким образом, если вы хотите обратиться к третьему полю, используйте $a[2] для извлечения третьего элемента.

Комментарии:

1. @Brett_Schneider Что, если в каждой строке есть строки в кавычках со встроенными запятыми?

2. @octopusgrabbus в вопросе ничего этого не говорится, поэтому я не вижу смысла тратить время на его обдумывание.

3. @Victor я рассмотрел это и, таким образом, расширил свой ответ до этого момента.

Ответ №3:

По возможности отделяйте синтаксический анализ от обработки и проверки ваших данных.

В этом случае, если у вас есть значения, разделенные запятыми, продолжайте и разделите эти значения. Тогда позаботьтесь о фильтрации ваших данных. Используете ли вы Text::CSV для синтаксического анализа, это отдельная проблема, хотя, вероятно, это хорошая идея.

 use strict;
use warnings;

while (<DATA>) {
    chomp;
    my @cols = split ',';

    if ($cols[0] =~ /^ENTRYNAME/) {
        print $cols[2], "n";
    }
}

__DATA__
ENTRYNAME-8,44544,99955,52,156,15:16:16,15:19:16
 

Выводит:

 99955