#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 )/;
}
На что стоит обратить внимание:
- В
while
состоянии цикла (и ТОЛЬКО в состоянии цикла while) чтение из дескриптора файла установит значение$_
равным и проверит, что файл был прочитан автоматически. - Оператор может быть изменен путем добавления
if
,unless
,for
,foreach
,while
, илиuntil
в его конец. Затем он работает как условный цикл или цикл для этого одного оператора. - Вы, вероятно, знаете, что группы захвата регулярных выражений хранятся в
$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
добавить к этому, чтобы избежать ошибок.