Getting position from unpack (was: "join on space instead of comma")

J

J. Romano

Tassilo said:
here's one that I find useful, namely the '/' construct.
The template preceeding the slash is used as a count
argument for the template following the slash:

Note how this can be combined with @:

my @x = unpack '@2c/C', "\x03\x00\x01\xff\x03";
print "@x\n",
__END__
255

Before that thread, I wasn't aware that I could use '@' like that
to start the position of unpacking. Before I learned about '@', I
would always use substr() to remove the beginning part of the string
that I wanted to ignore.

But that brings me to another question, one that concerns the usage
of the '/' construct. I've used that construct before, but I could
never find an easy way to figure out my offset into the string after
I've used it.

Let me clarify with an example. Say I have the following piece of
code:

my $string = "\x00\x01\x03\x00\x01\xff\x01\x0f";
# or I could say: my $sring = v0.1.3.0.1.255.1.15;
my @x = unpack '@2 c/C', $string;

That would make @x have three elements: 0, 1, and 255.

Now let's say that, after examining the contents of @x, I decide to
read in data for @y, starting where @x left off:

my @y = unpack '@6 c/C', $string;

That would make @y have only one element: 15.

However, in order to know that the second unpack command must start
at offset 6, I would have to calculate how many elements are in @x,
multiply that number by the space each element in @x takes (that is,
took up in the packed string), and add it to 2 (the first unpack()
offset) and add 1 (for the 'c' construct). (This may not be too
complicated to do now, but it would be much more difficult to do with
a more complex unpack string, like "w/(c4 i L Z20)".)

Is there a way for an unpack string to return the offset so that a
second unpack string can use it with the '@' construct? This would
make dealing with variable-length extractions (for example, with 'w/'
and 'Z*') much easier. I have read the "perldoc -f pack" and "perldoc
perlpacktut" pages but couldn't find anything about it (but maybe I
missed something).

Thanks in advance for any help.

-- Jean-Luc
 
A

Anno Siegel

J. Romano said:
Before that thread, I wasn't aware that I could use '@' like that
to start the position of unpacking. Before I learned about '@', I
would always use substr() to remove the beginning part of the string
that I wanted to ignore.

But that brings me to another question, one that concerns the usage
of the '/' construct. I've used that construct before, but I could
never find an easy way to figure out my offset into the string after
I've used it.

Let me clarify with an example. Say I have the following piece of
code:

my $string = "\x00\x01\x03\x00\x01\xff\x01\x0f";
# or I could say: my $sring = v0.1.3.0.1.255.1.15;
my @x = unpack '@2 c/C', $string;

That would make @x have three elements: 0, 1, and 255.

Now let's say that, after examining the contents of @x, I decide to
read in data for @y, starting where @x left off:

my @y = unpack '@6 c/C', $string;

That would make @y have only one element: 15.

However, in order to know that the second unpack command must start
at offset 6, I would have to calculate how many elements are in @x,

[snip discussion]

That's hard to do, though I think there's a module that calculates the
length of the storage image of pack/unpack templates.

In this case it isn't even necessary. Just make a copy of the rest of the
string using an additional "a*" template.

my $string = "\x00\x01\x03\x00\x01\xff\x01\x0f";
my @x = unpack '@2 c/C a*', $string;
$string = pop @x;

Now $string contains whatever wasn't consumed by the template before
"a*". So

my @y = unpack 'c/C', $string;

gives the right result without explicitly calculating an offset.

Anno
 
J

J. Romano

In this case it isn't even necessary. Just make a copy of the rest
of the string using an additional "a*" template.

my $string = "\x00\x01\x03\x00\x01\xff\x01\x0f";
my @x = unpack '@2 c/C a*', $string;
$string = pop @x;

Hey, thanks, Anno! Your solution is a lot more elegant (and works
far better) than the one I was thinking about.

Of course, if I wanted to find the position after the "@2 c/C"
template without modifying $string, I could do so very easily (by
basically using your technique) like this:

my $string = "\x00\x01\x03\x00\x01\xff\x01\x0f";
my @x = unpack "@2 c/C a*", $string;
my $position = length($string) - length(pop @x);

That way I can start unpacking $string again at $position.

Thanks again!

-- Jean-Luc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top