2009-05-04 4 views
4

Цель поиска регулярных выражений состоит в том, чтобы определить все экземпляры класса шаблона из файлов заголовков C++. Экземпляры класса могут быть formarted, такие как:Как я могу получить несколько воспоминаний из регулярного выражения Perl?

CMyClass<int> myClassInstance; 

CMyClass2< 
int, 
int 
> myClass2Instacen; 

Поиск осуществляется путем загрузки всего файла в строку:

open(FILE, $file); 
$string = join('',<FILE>); 
close(FILE); 

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

$search_string = "\s*\w[^typename].*<(\s*\w\s*,?\n?)*)>\s*\w+.*"; 
$string =~ m/$search_string/; 

проблема заключается в том, что поиск возвращает один хит только даже если несколько экземпляров класса существуют в файлах.

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

ответ

3

Что вам нужно, это модификатор \G. Он начнет следующий матч вашей строки после последнего совпадения.

Вот документация из Perl Doc (SO возникли проблемы с ссылкой, так что вы должны скопировать и вставить):

http://perldoc.perl.org/perlfaq6.html#What-good-is- «% 5cG'-в-регулярного выражения % 3f

+0

Прямая ссылка на раздел, на который ссылается: http://perldoc.perl.org/perlfaq6.html#What-good-is-%27\G%27-in-a-regular-expression%3f –

7

Во-первых, если вы собираетесь обрабатывать файлы, вы должны использовать File::Slurp. Тогда вы можете сделать:

my $contents = read_file $file; 

read_file будет прогибаться по ошибке.

Во-вторых, [^ typename] не исключает только строку 'typename', но также и любую строку, содержащую любой из этих символов. Помимо этого, для меня не очевидно, что шаблон, который вы используете, будет последовательно соответствовать тем вещам, которые вы хотите, чтобы соответствовать, но я не могу комментировать это прямо сейчас.

Наконец, чтобы получить все матчи в файле по одному, используйте модификатор г в цикле:

my $source = '3 5 7'; 

while ($source =~ /([0-9])/g) { 
    print "$1\n"; 
} 

Теперь, когда я имел возможность взглянуть на свой образец, я до сих пор не уверен, что сделать из [^ TypeName], но вот пример программы, которая захватывает часть между угловыми скобками (как это, кажется, единственное, что вы захватываете выше):

use strict; 
use warnings; 

use File::Slurp; 

my $pattern = qr{ 
    ^
    \w+      
    <\s*((?:\w+(?:,\s*)?)+)\s*> 
    \s* 
    \w+\s*; 
}mx; 

my $source = read_file \*DATA; 

while ($source =~ /$pattern/g) { 
    my $match = $1; 
    $match =~ s/\s+/ /g; 
    print "$match\n"; 
} 

__DATA__ 
CMyClass<int> myClassInstance; 

CMyClass2< 
int, 
int 
> myClass2Instacen; 

C:\Temp> t.pl 
int 
int, int 

Теперь я предположим, что вы предпочтете следующее:

my $pattern = qr{ 
    ^
    (
     \w+      
     <\s*(?:\w+(?:,\s*)?)+\s*> 
     \s* 
     \w+ 
    ) 
    \s*; 
}mx; 

, который дает:

C:\Temp> t.pl 
CMyClass<int> myClassInstance 
CMyClass2< int, int > myClass2Instacen 
0

Я хотел бы сделать что-то вроде этого,


#!/usr/bin/perl -w 
use strict; 
use warnings; 

local(*F); 
open(F,$ARGV[0]); 
my $text = do{local($/);}; 
my (@hits) = $text =~ m/([a-z]{3})/gsi; 

print "@hits\n"; 

предполагая, у вас есть какой-то текстовый файл, как,

 
/home/user$ more a.txt 
a bb dkl jidij lksj lai suj ldifk kjdfkj bb 
bb kdjfkal idjksdj fbb kjd fkjd fbb kadfjl bbb 
bb bb bbd i 

это будет распечатать все обращения из регулярного выражения:


/home/user$ ./a.pl a.txt 
dkl jid lks lai suj ldi kjd fkj kdj fka idj ksd fbb 
kjd fkj fbb kad fjl bbb bbd 


и конкретное решение для вашей проблемы, используя тот же подход, может выглядеть,


#!/usr/bin/perl -w                           
use strict; 
use warnings; 

my $text = <<ENDTEXT; 
CMyClass<int> myClassInstance; 

CMyClass2< 
int, 
int 
> myClass2Instacen; 


CMyClass35< 
int, 
int 
    > myClass35Instacen; 

ENDTEXT 

my $basename = "MyClass"; 
my (@instances) = $text =~ m/\s*(${basename}[0-9]*\s*\<.*?                 
          (?=\>\s*${basename})                   
          \>\s*${basename}.*?;)/xgsi; 

for(my $i=0; $i<@instances; $i++){ 
    print $i."\t".$instances[$i]."\n\n"; 
} 

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

+0

open my $ fh, $ ARGV [0] лучше, чем местный (* F); open (F, $ ARGV [0]); использование Perl :: критика ваших примеров. –

+0

Я пробовал Perl :: Критик моих примеров (немного хлопот для установки), но он не дает никаких комментариев/предупреждений/ошибок для моего примера. Кроме того, я заметил, что блок pre и code неправильно экранирует левые угловые скобки ... – si28719e

Смежные вопросы