0
votes

I have a string say

my $str = 'click brick trick again';

Here is I'm trying something on this string

if ($str =~ /((?:[a-z]+ck\s*)+)(\s?again)/){
    print "#$1#$2#\n";
}

which prints: #click brick trick #again#
Now I want the space at start of $2. But it is captured in $1. What shall I do so that the space before again is captured in $1 while space is optional. Is there any way to do it? Is there any operator precedence that allow it?

3

3 Answers

1
votes

Move the optional space you were matching at the end of the words to the front of the word:

((?: ?[a-z]+ck)+)( ?again)
0
votes

Here are 4 different ways to get the behavior that you desire:

use strict;
use warnings;

my $str = 'click brick trick again';

# Original Regex
print "#$1#$2#\n" if $str =~ /((?:[a-z]+ck\s*)+)(\s?again)/;

# Explicitly specify word followed by optional other words
print "#$1#$2#\n" if $str =~ /([a-z]*ck(?:\s+[a-z]*ck)*)(\s+again)/;

# Force "again" to be preceeded by at least one space using `+` instead of `?`
print "#$1#$2#\n" if $str =~ /((?:[a-z]+ck\s*)+)(\s+again)/;

# No Trailing spaces by using a lookbehind assertion
print "#$1#$2#\n" if $str =~ /((?:[a-z]+ck\s*)+)(?<!\s)(\s+again)/;

# No Leading spaces by using a lookahead assertion
print "#$1#$2#\n" if $str =~ /(?!\s)((?:\s*[a-z]+ck)+)(\s+again)/;

Outputs:

#click brick trick #again#
#click brick trick# again#
#click brick trick# again#
#click brick trick# again#
#click brick trick# again#
0
votes

Perl pattern matching is (generally) greedy - non greedy pattern matching is computationally expensive.

However, I'd suggest stepping away from the regular expressions, because it sounds like what you're trying to do is - at best - going to be a complicated RE, and that's generally bad for maintainability.

However, what you probably want (from perlre):

*?        Match 0 or more times, not greedily
+?        Match 1 or more times, not greedily
??        Match 0 or 1 time, not greedily