8

How can I rewind the start of the next search position by 1? For example, suppose I want to match all digits between #. The following will give me only odd numbers.

my $data="#1#2#3#4#";

while ( $data =~ /#(\d)#/g ) {
  print $1, "\n";
}

But if I could rewind the start of the next position by 1, I would get both even and odd numbers.

This doesn't work: pos() = pos() - 1;

I know I can accomplish this using split. But this doesn't answer my question.

for (split /#/, $data) {
  print $_, "\n";
}
n.r.
  • 1,900
  • 15
  • 20

2 Answers2

12

One approach is to use a look-ahead assertion:

while ( $data =~ /#(\d)(?=#)/g ) {
  print $1, "\n";
}

The characters in the look-ahead assertion are not part of the matched expression and do not update pos() past the \d part of the regular expression.

More demos:

say "#1#2#3#4#" =~ /#(\d)/g;          #  1234
say "#1#2#3#4"  =~ /#(\d)/g;          #  1234
say "#1#2#3#4#" =~ /#(\d)(?=#)/g;     #  1234
say "#1#2#3#4"  =~ /#(\d)(?=#)/g;     #  123
ikegami
  • 367,544
  • 15
  • 269
  • 518
mob
  • 117,087
  • 18
  • 149
  • 283
  • 5
    While this doesn't answer the question as posed, it is a better solution to what the OP is trying to do. – cjm Jul 21 '15 at 15:48
  • 1
    I am constantly amazed that people can read this gibberish. That top while loop - not a clue WTF it does. – Alec Teal Jul 21 '15 at 20:04
  • Luckily you're in the right place as SO users can give you answers to all kind of programming questions. – mpapec Jul 21 '15 at 21:28
  • 2
    @Alec Teal, Chinese appears to be gibberish to someone who only knows English, but it's not, and it's rude to say it is. Rather than proudly announcing your ignorance, perhaps you should seek education? `/.../` matches the regex pattern within against the variable bound by the `=~` operator (`$data`, in this case). In scalar context (as it is here), it returns true if there is match. In scalar context, the `g` option causes the position at which the match ended to be saved as the starting position of the next attempt. – ikegami Jul 22 '15 at 05:52
  • A better explanation of look-ahead assertions can be found at https://www.regular-expressions.info/lookaround.html – A T - student Nov 21 '19 at 23:12
8

You're calling pos() on $_, instead of $data

From perldoc

Returns the offset of where the last m//g search left off for the variable in question ($_ is used when the variable is not specified)

So,

pos($data) = pos($data) - 1;
mpapec
  • 50,217
  • 8
  • 67
  • 127