Perl извлекает совпадения из списка

#perl

#perl

Вопрос:

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

 FLAG(123)
FLAG(456)
Not a flag
FLAG(789)
  

Я хотел бы извлечь список [123, 456, 789]

Очевидно, что регулярное /^FLAG((w )/ выражение. Мой вопрос в том, какой простой способ извлечь эти данные в perl?

Очевидно, что нетрудно настроить цикл и выполнить несколько =~ совпадений, но я довольно много слышал о краткости perl и о том, что у него есть оператор для всего, поэтому мне интересно, есть ли простой и простой способ сделать это.

Кроме того, можете ли вы указать мне хорошую ссылку на perl, где я могу найти простые способы делать другие подобные вещи, когда появится следующая возможность? В Интернете есть много ресурсов perl, но 90% из них слишком просты, а остальные 10%, похоже, теряют сигнал в шуме.

Спасибо!

Ответ №1:

Вот как я бы это сделал… Узнали ли вы что-нибудь новое и / или полезное?

 my $file_name = "somefile.txt";
open my $fh, '<', $file_name or die "Could not open file $file_name: $!";

my @list;
while (<$fh>)
{
    push @list, $1 if /^FLAG((w )/;
}
  

На что стоит обратить внимание:

  1. В while состоянии цикла (и ТОЛЬКО в состоянии цикла while) чтение из дескриптора файла установит значение $_ равным и проверит, что файл был прочитан автоматически.
  2. Оператор может быть изменен путем добавления if , unless , for , foreach , while , или until в его конец. Затем он работает как условный цикл или цикл для этого одного оператора.
  3. Вы, вероятно, знаете, что группы захвата регулярных выражений хранятся в $1 , $2 , и т.д., Но вы, возможно, не знали, что оператор будет работать, даже если оператор имеет if суффикс. Сначала if вычисляется, поэтому push @list, $1 if /some_regex/ имеет смысл и сначала выполнит сопоставление, присваивая значение $1 до того, как оно потребуется в push инструкции.

Ответ №2:

Предполагая, что у вас есть все данные вместе в одной строке:

 my @matches = $data =~ /^FLAG((w )/mg;
  

/g Модификатор означает совпадение как можно больше раз, /m делает ^ совпадение после любой новой строки (не только в начале строки), а совпадение в контексте списка возвращает все записи для всех этих совпадений.

Если вы читаете данные построчно, то решение Platinum Azure — это то, что вам нужно.

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

1. 1 для учета случая с одной строкой, о котором я не подумал.

Ответ №3:

map здесь твой друг.

 use strict;
use warnings;
use File::Slurp;

my @matches = map { /^FLAG((w )/ } read_file('file.txt');
  

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

1. Предположительно, для этого требуется иметь все содержимое file.txt в памяти. Может быть проблема с большим файлом. 🙂

2. Прохладный. Я не знал, что применение регулярного выражения приводит к возвращению первого совпадения. Я полагаю, что если ваше регулярное выражение имеет несколько групп совпадений, то результатом будет скаляр скаляров? Спасибо!

3. На самом деле, я не уверен, что это сработает. Прежде всего, в скалярном контексте регулярное выражение возвращает значение false для несоответствия и значение true для совпадения. В контексте списка он вернет группы (или совпадения, если используется g опция), но также вернет undef отсутствие совпадений. Не @matches будет содержать undef для всех строк, которые не совпадают? Я думаю, вам нужно grep добавить к этому, чтобы избежать ошибок.