Как мне сопоставить несколько строк в perl - PullRequest
1 голос
/ 21 февраля 2020

Допустим, у меня есть файл списка соединений, отформатированный так для каждого модуля:

module module_name1(in1, in2,
    in3, in4, in5,
    out1, out2, out3
    out4, out5);

В списке соединений их много. Я хочу иметь возможность получить имя модуля и список портов. Вот что у меня есть:

use strict;
use warnings;

my $input_file = $ARGV[0];
open (my $INFILE, $input_file) or die "$input_file cannot be opened.\n";

my $outfile = "verilog.port.txt";
open (my $OUTFILE, '>', $outfile) or die "\nUnable to create $outfile\n";

my ($module_name,$port_list);

while (<>) {
  if ($_ =~ /module (\w+)\((.+)\)/m) {
    $module_name = $1;
    $port_list = $2;
    print $OUTFILE "Module Name: $module_name Port list: $port_list\n"
  }
}
close $INFILE;

close $OUTFILE;

Это будет работать только в том случае, если модуль создан только в 1 строке. Например, если:

module module_name2(in1, in2, out1, out2);

и я получу что-то вроде:

Module Name: module_name2 Port list: in1, in2, out1, out2

Однако, если модуль создан в несколько строк, как в моем первом примере, мое выражение reg не может его выбрать вверх. Поэтому мне было интересно, есть ли способ сопоставления нескольких строк, используя perl.

Ответы [ 3 ]

3 голосов
/ 21 февраля 2020

Вы читаете файлы построчно, вам нужно прочитать их либо по абзацу (куски, разделенные пустой строкой), либо весь файл, если такого разделения нет; в противном случае $_ содержит только одну строку и не будет совпадать.

Кроме того, флаг /m - это не то, что вы ищете (/m делает ^ / $ соответствует началу / концу строк), вам нужно /s, что делает . включать переводы строки (см. страницу документации perlreref , страница perlop немного сбивает с толку)

По абзацу, этот один вкладыш должен сделать свое дело:

$ perl -l -00 -ne 'if ( /module (\w+)\((.+)\)/s) { @ports = split(/\s*,\s*/,$2); print "Module name: $1 Ports: " . join(", ", @ports)}' <<'EOF'
> module module_name1(in1, in2,
>     in3, in4, in5,
>     out1, out2, out3,
>     out4, out5);
>
>
> module module_name2(in21, in22,
>     in23, in24, in25,
>     out21, out22, out23,
>     out24, out25);
> EOF
Module name: module_name1 Ports: in1, in2, in3, in4, in5, out1, out2, out3, out4, out5
Module name: module_name2 Ports: in21, in22, in23, in24, in25, out21, out22, out23, out24, out25

Вы можете использовать -MO=Deparse, чтобы увидеть весь код:

perl -MO=Deparse -l -00 -ne 'if ( /module (\w+)\((.+)\)/s) { @ports = split(/\s*,\s*/,$2); print "Module name: $1 Ports: " . join(", ", @ports)}'
BEGIN { $/ = ""; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    if (/module (\w+)\((.+)\)/s) {
        @ports = split(/\s*,\s*/, $2, 0);
        print "Module name: $1 Ports: " . join(', ', @ports);
    }
}

Если у вас нет пустых строк, разделяющих модули, вам нужно получить весь файл сразу ( slurp)

perl -l -0777 -ne 'while (/module (\w+)\((.+?)\);/sg) { @ports = split(/\s*,\s*/,$2); print "Module name: $1 Ports: " . join(", ", @ports)}' <<'EOF'
> module module_name1(in1, in2,
>     in3, in4, in5,
>     out1, out2, out3,
>     out4, out5);
> module module_name2(in21, in22,
>     in23, in24, in25,
>     out21, out22, out23,
>     out24, out25);
> EOF
Module name: module_name1 Ports: in1, in2, in3, in4, in5, out1, out2, out3, out4, out5
Module name: module_name2 Ports: in21, in22, in23, in24, in25, out21, out22, out23, out24, out25

Опять же, вы можете использовать -MO=Deparse, чтобы увидеть, что происходит:

perl -MO=Deparse -l -0777 -ne 'while (/module (\w+)\((.+?)\);/sg) { @ports = split(/\s*,\s*/,$2); print "Module name: $1 Ports: " . join(", ", @ports)}'
BEGIN { $/ = undef; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    while (/module (\w+)\((.+?)\);/gs) {
        @ports = split(/\s*,\s*/, $2, 0);
        print "Module name: $1 Ports: " . join(', ', @ports);
    }
}

Ключевым элементом в этих подходах является -0 флаг, который в форме -00 устанавливает $/ в пустую строку, активирующую режим абзаца, а в -0777 форме устанавливает $/ в неопределенное состояние, включающее режим глухоты (чтение всего файла) (см. также: $ RS в руководстве по perlvar.)

Важное предупреждение: -l устанавливает переменную $\ равной $/ (которая по умолчанию это «\ n»), и в этом случае он должен использоваться перед -0 в командной строке, если вы хотите, чтобы вывод был разделен новыми строками.

Для более элегантного подхода вы можете использовать следующий скрипт:

#!/bin/perl

use warnings;
use strict;

use File::Slurp;
use Data::Dumper;

my $data = read_file($ARGV[0]);

my %modules = $data =~ /module (\w+)\((.+?)\);/sg;

$modules{$_} = [split(/\s*,\s*/, $modules{$_})] for keys(%modules);

print Dumper(\%modules);

Это даст вам структуру данных, содержащую всю необходимую информацию - см. https://ideone.com/BuuR8I для живого демо

0 голосов
/ 22 февраля 2020

Я должен не согласиться с тем, что построчное чтение 'неуместно', когда perl имеет оператор диапазона .. .

Возьмите код OP и измените его так :

while (<>) {
    if (/module/ .. /\)/) {
        $module_name = $1 if /module\s+(\w+)/;
        my $done=/\)/;
        s/.*\(//; s/\).*//;s/,\s+/, /g;
        chomp;
        $port_list .= $_;
        print $OUTFILE "Module Name: $module_name Port list $port_list\n" if $done;
    }
}

Другими словами, от строк, соответствующих /module/, до строк, соответствующих /)/, накапливается список портов.

0 голосов
/ 21 февраля 2020

См. Следующий фрагмент кода для одного из многих возможных решений.

ПРИМЕЧАНИЕ. В блоке разнесенных данных отсутствует OP , после out3

#!/usr/bin/perl 
#
# vim: ai:ts=4:sw=4
#

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $debug = 0;          # debug flag

my $data = do { local $/; <DATA> };

$data =~ s/[ \n]+/ /g;

my @lines = split ';', $data;

say Dumper(\@lines) if $debug;

for (@lines) {
    next unless /module\s+(.*)?\((.*)\)/;
    say "Module: $1 -- Ports: $2";
}


__DATA__
module module_name1(in1, in2,
    in3, in4, in5,
    out1, out2, out3,
    out4, out5);


module module_name2(in21, in22,
    in23, in24, in25,
    out21, out22, out23,
    out24, out25);

Вывод

Module: module_name1 -- Ports: in1, in2, in3, in4, in5, out1, out2, out3, out4, out5
Module: module_name2 -- Ports: in21, in22, in23, in24, in25, out21, out22, out23, out24, out25
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...