Использование регулярного выражения в Perl для перечисления переменных из другого скрипта Perl - PullRequest
2 голосов
/ 01 марта 2010

Мои мысли о том, как извлечь все скаляры и массивы из файла Perl, звучали так:

open (InFile, "SomeScript.pl");
@InArray = <InFile>;
@OutArray = {};
close (InFile);
$ArrayCount = @InArray;
open (OutFile, ">outfile.txt");
for ($x=0; $x<=$ArrayCount; $x++){
$Testline = @InArray[$x];

if($Testline =~ m/((@|\$)[A-Z]+)/i){
    $Outline = "$1\n";  
    push @OutArray, $Outline;
}
}
print OutFile @OutArray;
close(OutFile);

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

$FirstVar = $SecondVar + $ThirdVar;

Скрипт будет только захватывать $FirstVar и выводить в файл. Это может все же работать, потому что $SecondVar и $ThirdVar должны быть инициализированы где-то еще, прежде чем исходная строка не будет иметь никакого значения Я предполагаю, что исключением из правила будет строка, в которой несколько переменных инициализируются одновременно.

Может ли пример в реальном коде Perl сломать этот скрипт? Кроме того, как получить несколько элементов, которые соответствуют критериям моего регулярного выражения, из одной строки?

Ответы [ 5 ]

9 голосов
/ 01 марта 2010

Не делай этого

Вы не можете разобрать Perl с регулярными выражениями, поэтому я бы даже не попробовал.
Вы даже не можете правильно разобрать его, не запустив его, но вы можете приблизиться с помощью PPI .

perl-variables.pl

#! /usr/bin/env perl
use strict;
use warnings;
use 5.10.1;

use PPI;
use PPI::Find;

my($filename) = (@ARGV, $0); # checks itself by default

my $Doc = PPI::Document->new($filename);
my $Find = PPI::Find->new( sub{
  return 0 unless $_[0]->isa('PPI::Token::Symbol');
  return 1;
});

$Find->start($Doc);
while( my $symbol = $Find->match ){
  my $raw = $symbol->content;
  my $var = $symbol->symbol;
  if( $raw eq $var ){
    say $var;
  } else {
    say "$var\t($raw)";
  }
}
print "\n";

my @found = $Find->in($Doc);
my %found;
$found{$_}++ for @found;

say for sort keys %found;

Запустив его против себя, выдает:

$filename
@ARGV
$0
$Doc
$filename
$Find
@_  ($_)
$Find
$Doc
$symbol
$Find
$raw
$symbol
$var
$symbol
$raw
$var
$var
@found
$Find
$Doc
%found
%found  ($found)
$_
@found
%found

$0
$Doc
$Find
$_
$filename
$found
$raw
$symbol
$var
%found
@ARGV
@found
4 голосов
/ 01 марта 2010

Похоже, что при этом будут пропущены полностью определенные имена переменных ($My::Package::Foo) и редкие, но допустимые имена переменных, заключенные в фигурные скобки (${variable}, ${"varname!with#special+chars"}). Ваш сценарий также будет соответствовать элементам доступа к хэшам и массивам ($array[4] ==> $array, $hash{$key} ==> $hash) и вызовам метода объекта ($object->method() ==> $object), которые может или не может быть то, что вы хотите.

Вы также не соответствуете переменным с подчеркиванием ($my_var) и числами ($var3), и вы можете получить ложные срабатывания из комментариев, строк в кавычках, модуля и т. Д. (# report bugs to bob@company.org).

Для сопоставления нескольких выражений необходимо использовать модификатор /g, который вернет список совпадений:

@vars = $Testline =~ /[@\$]\w+/gi;
if (@vars > 0) {
  push @OutArray, @vars;
}
1 голос
/ 01 марта 2010

Время простой ответ на флаг / g на вашем регулярном выражении.

Сложный ответ заключается в том, что этот вид анализа кода очень сложен для Perl. Посмотрите на модуль PPI для лучшего, более полнофункционального, семантического анализа кода Perl.

0 голосов
/ 01 марта 2010

Несмотря на ограничения, связанные с этим методом, ниже приведена несколько более простая версия скрипта, которая читает из стандартного ввода.

#!/usr/bin/perl
use strict;
use warnings;
my %vars;

while (<>) {
  $vars{$_}++ for (m'([$@]\w+)'g);
}

my @vars = keys %vars;
print "@vars\n";
0 голосов
/ 01 марта 2010

Я не могу ответить ни на один из ваших вопросов напрямую, но я предложу следующее: я не знаю, почему вы пытаетесь извлечь скаляры, но пакет отладчика, который поставляется с perl, должен «знать» обо всех переменных , и в последний раз, когда я посмотрел, это было написано на Perl. Возможно, вам лучше попытаться оценить сценарий perl, используя пакет отладчика или методы, заимствованные из этого пакета, а не изобретать колесо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...