use Test::More; my @test = ( [ '1 This (is a test) with good parens' => 'is a test', 'Match in parens' ], [ '2 This is a (test with broken a paren' => 'test with broken a paren', 'Match after left paren' ], [ '3 And this would be one) the other way' => '3 And this would be one', 'Match before right paren' ], [ '4 Lastly, no parens' => '', 'No match' ], ); foreach my $test (@test) { my $got = match( $test->[0] ); is( $got, $test->[1], "$test->[2]: <<$got>>" ); } done_testing(); sub match { for (shift) { m/ \(([^)]*?)\) /x && return $1; # Both parens. m/ \((.*)$ /x && return $1; # Left paren. m/ ^(.*)\) /x && return $1; # Right paren. m/ ^[^()]*()$ /x && return $1; # No parens (no capture). return; # Unreachable. } } #### sub match { local $_ = shift; m/ \(([^)]*?)\) /x # Both parens. || m/ \((.*)$ /x # Left paren. || m/ ^(.*)\) /x # Right paren. || m/ ^[^()]*()$ /x; # No parens (no capture). return $1 // (); } #### sub match { shift =~ m/ (?: [^(]*\((?[^)]*?)\) ) # Both parens. | (?: \((?.*)$ ) # Left paren. | (?: ^(?.*)\) ) # Right paren. | (?: ^[^()]*(?)$ ) # No parens (empty capture). /x; return $+{C} // (); } #### sub match { shift =~ m/ (?: [^(]*\(([^)]*?)\) ) # Both parens. | (?: \((.*)$ ) # Left paren. | (?: ^(.*)\) ) # Right paren. | (?: ^[^()]*()$ ) # No parens (empty capture). /x; return $^N // (); } #### sub match { shift =~ m/ (?| (?: [^(]*\(([^)]*?)\) ) # Both parens. | (?: \((.*)$ ) # Left paren. | (?: ^(.*)\) ) # Right paren. | (?: ^[^()]*()$ ) # No parens (empty capture). ) /x; return $1 // (); } #### sub match { shift =~ m/ (?| [^(]*\(([^)]*?)\) # Both parens. | \((.*)$ # Left paren. | ^(.*)\) # Right paren. | ^[^()]*()$ # No parens (empty capture). ) /x; return $1 // (); }