2017-12-12 18 views
3

私はまだPerlを学んでいるので、明らかな質問であれば謝ります。 括弧で囲まれていないテキストと一致する方法はありますか? たとえば、fooを検索すると2行目と一致します。括弧で囲まれていない一致するテキスト

(bar foo bar) 
bar foo (
bar foo 
    (bar) (foo) 
) 
+0

あなたは否定的な先読みを使用していますか? – Boschko

答えて

4

これは「明白」とは非常に遠く離れています。それどころか。複雑なパターンには「一致しない」と言う直接的な方法はありません(文字レベルでのサポートは[^a]\Sなど)。正規表現はまず第一にマッチするものであり、マッチングしないものではありません。

1つのアプローチは、それらの(おそらくネストされた)区切り文字にマッチさせ、それ以外のすべてを取得することです。

ネストされたデリミタを見つけるための優れたツールは、コアモジュールText::Balancedです。一致すると、マッチの前の部分文字列とマッチ後の残りの文字列を与えることもできます。

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

use Text::Balanced qw(extract_bracketed); 

my $text = <<'END'; 
(bar foo bar) 
bar foo (
bar foo 
    (bar) (foo) 
    ) 
END 

my ($match, $before); 
my $remainder = $text; 
while (1) { 
    ($match, $remainder, $before) = extract_bracketed($remainder, '(', '[^(]*'); 
    print $before // $remainder; 
    last if not defined $match; 
} 
extract_bracketed

リターンマッチ、前サブストリング残り($remainder)、およびサブストリング($before)。私たちは残りの部分で一致を維持します。

this postより詳細と別の方法がありますが、Regexp::Commonを使用してください。

+0

私はこのモジュールについて知らなかった。ありがとう!ところが、 '$ text'や' $ lead'の内部でマッチすると、行番号を見つけるのが難しいと感じています。 1つの方法は、 '$ match'で改行文字の数を数えることです。しかし、より良い方法がありますか? – Tohiko

+1

@Tohikoようこそ。ソース内の文字/行が見つかりましたか? '$ lead'(または' $ text')の中で '\ n'を数えれば、ソースにある行は通知されません。私はそれを調べます。 – zdim

+0

@Tohiko '$ lead'を' $ before'に、 '$ text'を' $ remainder'に変更しました。 – zdim

5

正規表現パターンの暗黙の先頭は\G(?s:.)*?です(「一致するまで文字をスキップする」)。以下では、その定義を展開して、ネストされた括弧をスキップする文字にすることを検討します。

while (
    $string =~ m{ 
     \G (?&MEGA_DOT)*? 

     (foo) 

     (?(DEFINE) 
     (?<MEGA_DOT> [^()] | \((?&MEGA_DOT)*+ \)) 
    ) 
    }xg 
) { 
    say "Found a match at pos $-[1]."; 
} 
+0

魅力的!しかし、私はこれが理由で人々がPerlを嗅ぐと恐れていると思っています... ;-) – PerlDuck

+1

@ PerlDuck、実際には、Perlがどのようにシンプルで構造化されているかは驚くべきことです。 – ikegami

+0

初心者として私はこれを理解することができませんでしたので、親切に学習するための詳細な方法論を提供してください。 – ssr1012

関連する問題