Problem With Split
debiandude
created: 2004-06-16 08:27:57

I have a string that is eight numbers and I would like to split it into two. I know that I could do it with substring but split seemed like a more logical choice. One way I did it was this:

my $thing = '12340019';
$thing = s/(\d{4})(\d{4})/$1 $2/;
my @splat = split(/ /, $thing);

But that doesn't really seem like the best way to do it. I figured that I should be able to get the effect by using split by itself and asking it to split on 4 numbers, but I couldn't get it to work. Also how would I go about changing '0019' into 19. Is sprintf the only (or best) way to accomplish that.

Thanks

Re: Problem With Split
created: 2004-06-16 08:35:52
how about:
my $thing = '12340019';
my @splat = $thing =~ m/\d{4}/g;
my $num = '0019';
$num = int $num;
Re^2: Problem With Split
created: 2004-06-16 08:45:14
Well the number changes each time so I couldn't just use int '0019'. Also my @splat = $thing =~ m/\d{4}/g; only sets @splt = ('1234');
Re^3: Problem With Split
created: 2004-06-16 08:54:50

Also my @splat = $thing =~ m/\d{4}/g; only sets @splt = ('1234');

That's funny, because:

my $thing = '12340019';
my @splat = $thing =~ m/\d{4}/g;

print Dumper \@splat;
__END__
$VAR1 = [
          '1234',
          '0019'
        ];

Cheers, Sören

Re^3: Problem With Split
created: 2004-06-16 09:13:19
Well the number changes each time so I couldn't just use int '0019'.
uh? so what's the problem? use int $num, like i showed you.
$num can be anything you want. this code will take a string consisting of digits with leading zeros and remove them. why would you think that it works only on the string '0019'?
Also my @splat = $thing =~ m/\d{4}/g; only sets @splt = ('1234');
see Happy-the-monk's answer. maybe your perl is broken.
Re^4: Problem With Split
created: 2004-06-16 10:27:19

It's not that I thought it only worked on the string '0019'. When I had first typed you code and did:

foreach (@splat) { print $_, "\n" }

I only saw 1234 printed, so I figured you then wrote the int '0019' because @splat = $thing =~ m/\d{4}/g; only sets the first one. However, I did it again, I really don't know what I changed, but it worked this time.

Thanks. And sorry for the confusion.

Re: Problem With Split
created: 2004-06-16 08:41:24

See also Adding formatting to a string posted today.

Cheers, Sören

Re: Problem With Split
created: 2004-06-16 09:02:48

Did you want integers?

  my $thing = '12340019';
  my @splat = map {int $_} $thing =~ /(\d{4})/g

Re: Problem With Split
created: 2004-06-16 09:07:38
If you are sure that your input will always be integers, you could use
my $thing = '12340019';
my @num01 = map{ int } $thing =~ m/(\d{4})/g;

PJ
We are drowning in information and starving for knowledge - Rutherford D. Rogers
What good is knowledge if you have to pull teeth to get it - anonymous
Re: Problem With Split
created: 2004-06-16 09:29:19
You can combine look behind and look ahead in the regex of the split:

#!/usr/local/bin/perl -w
use strict;

my $number = '00120034';

# split at the position that has 4 digits
# behind and 4 digits ahead

my ($n1, $n2) = split /(?<=\d{4})(?=\d{4})/, $number;

print "$n1, $n2\n";

# strip leading 0's
($n1, $n2) = map { int $_ } ($n1, $n2);

print "$n1, $n2\n";

And the output is as expected...
0012, 0034
12, 34


This technique is very useful. For example, you could comma'fy a floating point number with look ahead and look behind in one go, sort of... :-)
{
  local $_ = $amount;
  /\./ ? s/(?<=\d)(?=(\d{3})+(?:\.))/,/g : s/(?<=\d)(?=(\d{3})+(?!\d))/,/g;
  $amount = $_;
}

Re^2: Problem With Split
created: 2004-06-16 14:34:18
This technique is very useful

Lookahead and lookbehind are both very useful indeed, but I think your example is better solved with a sexeger:

$amount = reverse $amount;
$amount =~ s/(\d{3})/$1,/g;
$amount = reverse $amount;

Update: oops, I guess my example doesn't commafy a floating-point number, now does it? Oh well. At least maybe someone will learn about sexegers who didn't know about them. 8^)

Re^2: Problem With Split
created: 2004-06-16 14:59:50
Maybe you should submit that as a [2145|Q&A answer].

Here's another stab:

s{(?


We're not really tightening our belts, it just feels that way because we're getting fatter.
Re: Problem With Split
hv
created: 2004-06-16 09:30:03

[doc://split] is best used when you have a separator of some sort to split on. In this case there is no separator - you have a bunch of things packed together - so you'd probably be better off with [doc://unpack]:

  my @splat = unpack '(A4)*', $thing;

That is: unpack this string into (4-character substrings) as many as you can find. (If there can only be two such substrings, you can replace the '*' with '2' to specify that.) Note that this is just dealing with characters, it doesn't know anything about digits - if you need to locate the digits in the string first, you probably want a regular expression for that.

Once you have the right digits separated out, removing leading zeros is as simple as getting perl to treat it as a number. A couple of common idioms for doing that are:

  $num = int($string);
  $num = $string + 0;

With [doc://map] you can apply that transformation to the stream of strings on its way into the array:

  my @splat = map $_ + 0, unpack '(A4)*', $thing;

Hope this helps,

Hugo

Re^2: Problem With Split
created: 2004-06-16 11:33:59
Ahh.. I was unaware of the unpack function. Pretty cool. Thanks.
Re: Problem With Split
created: 2004-06-16 09:33:40
you could try unpack for this, given you seem to be looking for fixed length string processing. after all, why use vulgar regexen when the refined unpack is ready to help?

in the following i also use sprintf to deal with leading zeros.

print join ":", map {sprintf("%d",$_)} unpack("A4A4",shift);
...wufnik

-- in the world of the mules there are no rules --

perlmonks.org content © perlmonks.org and debiandude, Happy-the-monk, hv, pbeckingham, periapt, revdiablo, Roger, Roy Johnson, tinita, wufnik

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03