4

正規表現検索の目的は、C++ヘッダーファイルからすべてのテンプレートクラスインスタンスを判別することです。クラスインスタンスは、次のように形式化できます。

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/; 

問題は、ファイルにさらに多くのクラスインスタンスが存在する場合でも、検索で1つのヒットしか返されないことです。

正規表現の後方参照変数の1つからこのアプローチを使用して、すべてのヒットを取得することは可能ですか?

4

3 に答える 3

7

まず、ファイルを丸呑みする場合は、File::Slurpを使用する必要があります。次に、次のことができます。

my $contents = read_file $file;

read_fileはエラー時に鳴きます。

次に、[^ typename]は、文字列'typename'だけでなく、これらの文字のいずれかを含む文字列も除外します。それ以外は、使用するパターンが一貫して一致させたいものと一致するかどうかはわかりませんが、現時点ではコメントできません。

最後に、ファイル内のすべての一致を1つずつ取得するには、ループでg修飾子を使用します。

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
于 2009-05-04T14:01:12.903 に答える
3

必要なのは\G修飾子です。最後の一致の後に、文字列の次の一致を開始します。

Perl Doc のドキュメントは次のとおりです (SO はリンクに問題があるため、コピーして貼り付ける必要があります)。

http://perldoc.perl.org/perlfaq6.html#What-good-is- '%5cG'-in-a-regular-expression%3f

于 2009-05-04T13:49:34.553 に答える
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$ もっと a.txt
a bb dkl jidij lksj lai suj ldifk kjdfkj bb
bb kdjfkal idjksdj fbb kjd fkjd fbb kadfjl bbb
bb bb bbd私

これにより、正規表現からのすべてのヒットが出力されます。


/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";
}

もちろん、データのすべてのエッジケースに適合するように正規表現をもう少し調整する必要があるかもしれませんが、それはかなり良いスタートになるはずです.

于 2009-05-04T16:06:16.207 に答える