Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Re: Pack/unpack - understanding the '@' and '.' templactes

by Loops (Curate)
on Mar 31, 2013 at 07:11 UTC ( #1026338=note: print w/replies, xml ) Need Help??

in reply to [SOLVED] Pack/unpack - understanding the '@' and '.' templactes

Hi there,

So, the "@" repositions the pointer to which character will next be consumed from the expression string. You may pass a number to it.. so:

say unpack 'aaaaa@0aa', 'ABCDEFGH'; # prints ABCDEAB
Now, when it's inside a group, it doesn't move the pointer to the start of the expression, but back to where the current group started matching:
say unpack 'aa(aaa@0)aa', 'ABCDEFGH'; # prints ABCDECD
Now you'll notice I was supplying a 0 parameter to @, which means back to the very start of the string or group. But if you don't supply a number, 1 is used as a default.
say unpack 'aa(aaa@)aa', 'ABCDEFGH'; # prints ABCDEDE say unpack 'aa(aaa@1)aa', 'ABCDEFGH'; # prints ABCDEDE
So in your first example:
say unpack '(C/xa@)3', "\003\003\003abcdef"; # prints 'bcd'

C reads in the first byte (which is 3) which then is used as a length by /x to move over 3 bytes in the input expression where the 'a' reads the next character yielding "b". The @ having no numeric modifier, and being constrained in a group moves back to 1 byte from the starting point of where the group was anchored. Since the group is currently anchored on the very first character, the new starting point will be the second byte.

And the whole thing repeats but now anchored on this new starting point. The next time @ is met, it will move back to 1 byte from the current starting point... ie the 3rd byte.

In this way, the 3 offset bytes at the start of the input expression can each be scanned. We jump forward to process what each one references, and then we jump back to process the next offset.

Now to the "." character. It's kind of tricky. Essentially what it does is give you your current pointer position within the expression. So:
say unpack 'aa.', 'ABCDEFGH'; # prints AB2 say unpack 'aaaa.', 'ABCDEFGH'; # prints ABCD4
Now we can combine this with the '/' operator! Which will consume this number instead of sending it to the output:
say unpack 'aa./xaa', 'ABCDEFGH'; # prints ABEF
What happened? The first two 'a' print AB, the . returns '2' (as in the above example) but instead of being printed is consumed by the '/x' which moves the input pointer over by this 2 characters. Where the next two 'a' print EF. When used inside of a group, by default the '.' character will return to you the offset from the start of the group! But using the '*' modifier, we can escape the group and get it to act like it's not inside a group and return the absolute position from the start of the string:
say unpack 'aa.aa', 'ABCDEFGH'; # prints AB2CD say unpack 'a(a.a)a', 'ABCDEFGH'; # prints AB1CD say unpack 'a(a.*a)a', 'ABCDEFGH'; # prints AB2CD
And this should give you a hint about the answer to your second question. To return to the absolute start of the string, use the ".*" construct to get your current position combined with "/X" to move backward that many characters:
say unpack 'aa(aa).*/Xaa', 'ABCDEFGH'; # prints ABCDAB say unpack 'aa(aa.*/Xaa)', 'ABCDEFGH'; # prints ABCDAB

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1026338]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2018-10-17 04:51 GMT
Find Nodes?
    Voting Booth?
    When I need money for a bigger acquisition, I usually ...

    Results (90 votes). Check out past polls.