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
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
Outside of code tags, you may need to use entities for some characters:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.
| & || & |
| < || < |
| > || > |
| [ || [ |
| ] || ] |