\G (?<! \A) (?! \A) \G ... kind of hurts my brain ...
I got to wondering about all that and thought I might try to clarify it a bit, if only for my own benefit. Say we have the problem "match (and capture) the first \w character that is not at the start of the string and that is also on a \b boundary." From the foregoing discussion, m{ (?! \A) \b (\w) }xms does the trick:
c:\@Work\Perl\monks>perl -wMstrict -le
"print qq{'$1'} if 'ab-cd' =~ m{ (?! \A) (\w) }xms;
print qq{'$1'} if 'ab-cd' =~ m{ \b (\w) }xms;
print qq{'$1'} if 'ab-cd' =~ m{ (?! \A) \b (\w) }xms;
print qq{'$1'} if 'ab-cd' =~ m{ \b (?! \A) (\w) }xms;
"
'b'
'a'
'c'
'c'
Leaving out either zero-width assertion makes the match
fail | incorrect. The
order of the two assertions doesn't matter because it's a logical conjunction, and if there are no side-effects (and there aren't: we're just examining match position and not matching and consumng any characters, i.e., changing the match position), then
A and B and
B and A are equivalent expressions.
So what about the (?! \A) versus (?<! \A) look-ahead/behind business? Here's how I think of it: If you're at the North Pole, in which direction do you have to go to get to the North Pole? The question is moot: You can go exactly zero meters in any direction because you're at the North Pole! Similarly, if your match position is at the start of a string, in which direction do you have to "look" to "see" the | that you are at the start of the string? All you have to do is examine the match position; "direction" is meaningless. For the \A zero-width assertion, \A (?= \A) (?<= \A) are all exactly equivalent. The same reasoning applies to negated assertions: (?! \A) (?<! \A) are equivalent. Indeed, I think the same reasoning applies to all zero-width assertions. Here's a Test::More demo to bolster your confidence:
c:\@Work\Perl\monks>perl -wMstrict -le
"use Test::More 'no_plan';
use Test::NoWarnings;
;;
my @regexes = (
'negative look-ahead to \A',
qr{ (?! \A) \b (\w) }xms, qr{ \b (?! \A) (\w) }xms,
qr{ (?! \A) (?! \B) (\w) }xms, qr{ (?! \B) (?! \A) (\w) }xms,
qr{ (?! \A) (?<! \B) (\w) }xms, qr{ (?<! \B) (?! \A) (\w) }xms,
'negative look-behind to \A',
qr{ (?<! \A) \b (\w) }xms, qr{ \b (?<! \A) (\w) }xms,
qr{ (?<! \A) (?! \B) (\w) }xms, qr{ (?! \B) (?<! \A) (\w) }xms,
qr{ (?<! \A) (?<! \B) (\w) }xms, qr{ (?<! \B) (?<! \A) (\w) }xms,
'all together now',
qr{ \b (?! \A) (?! \B) (?<! \A) (?<! \B) (\w) }xms,
);
;;
REGEX:
for my $rx (@regexes) {
if (ref $rx ne 'Regexp') {
note $rx;
next REGEX;
}
'ab-cd' =~ $rx;
ok $1 eq 'c', qq{$rx works};
}
;;
done_testing;
"
# negative look-ahead to \A
ok 1 - (?msx-i: (?! \A) \b (\w) ) works
ok 2 - (?msx-i: \b (?! \A) (\w) ) works
ok 3 - (?msx-i: (?! \A) (?! \B) (\w) ) works
ok 4 - (?msx-i: (?! \B) (?! \A) (\w) ) works
ok 5 - (?msx-i: (?! \A) (?<! \B) (\w) ) works
ok 6 - (?msx-i: (?<! \B) (?! \A) (\w) ) works
# negative look-behind to \A
ok 7 - (?msx-i: (?<! \A) \b (\w) ) works
ok 8 - (?msx-i: \b (?<! \A) (\w) ) works
ok 9 - (?msx-i: (?<! \A) (?! \B) (\w) ) works
ok 10 - (?msx-i: (?! \B) (?<! \A) (\w) ) works
ok 11 - (?msx-i: (?<! \A) (?<! \B) (\w) ) works
ok 12 - (?msx-i: (?<! \B) (?<! \A) (\w) ) works
# all together now
ok 13 - (?msx-i: \b (?! \A) (?! \B) (?<! \A) (?<! \B) (\w) ) works
1..13
ok 14 - no warnings
1..14
Give a man a fish: <%-{-{-{-<