1

Why does this code:

my $text = "!a!b!c!";
my @captures = ($text =~ /!(.)!/g);
print "$_\n" foreach @captures;

output only

a
c

?

Expected output:

a
b
c

How can I capture all of them?

6
  • 2
    Use a lookahead in order not to consume the second !: ($text =~ /!(.)(?=!)/g);. However, your code outputs a and c, not only a. Commented Nov 14, 2015 at 21:31
  • Why not just do my @matches = split "!", "!a!b!c!"; Commented Nov 14, 2015 at 21:33
  • @hwnd this was just an abstract problem in trying to better understand captures, but your approach is useful as well thanks Commented Nov 14, 2015 at 21:38
  • @stribizhev thank you! Commented Nov 14, 2015 at 21:38
  • 1
    I would expect it to output "a\nc\n". And testing here, that's what I get. Is that really the code you're running, and are you really not getting the "c"? If so: What version of perl are you using, and how are you running this code? Commented Nov 14, 2015 at 23:52

1 Answer 1

2

You need to use a look-ahead in order not to consume the second ! and keep it for the next regex engine iteration:

/!(.)(?=!)/g

First, ! is matched, then any symbol but a newline that is right before a ! that is not consumed, the regex engine index stays right before it. So, the next match can start with this !.

Updated code:

my $text = "!a!b!c!";
my @captures = ($text =~ /!(.)(?=!)/g);
print "$_\n" foreach @captures;

Output:

a
b
c

Splitting with ! can turn out a more effecient alternative in the currently posted scenario:

my $text = "!a!b!c!";
my @matches = grep /\S/, split "!", $text;
print "$_\n" foreach @matches;

Note that grep /\S/ will remove empty or whitespace-only elements from the array obtained with split.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.