Ritesh Kumar Gupta
Ritesh Kumar Gupta

Reputation: 5191

String partitioning (converting complex string to an array) in perl

There is a large string s, that contains item codes which are comma delimited.

e.g.:

$s="90320,328923,SKJS32767,DSIKUDIU,829EUE,AUSIUD0Q897,AJIUE98,
387493420DA,93RE,AKDJ93,SADI983,90439,JADKJ84";

In my application these strings are passed to a function, which returns the price of these items, i.e. the output of the function is corresponding price for the item code input.

However, due to certain limitations, the maximum length of $s should not exceed 16. If the length of $s exceeds 16, then an exception is thrown. Thus, these strings should be partitioned into an array, such that, the length of each element of array is less than or equal to 16.

e.g: After partitioning $s, the array is:

$Arr[0]='90320,328923',#Note First 16 char is 0320,328923,SK. 
However, SK is neglected as its an incomplete(being partial) item code.
$Arr[1]='SKJS32767',
$Arr[2]='DSIKUDIU,829EUE',
$Arr[3]='AUSIUD0Q897',
$Arr[4]='AJIUE98',
$Arr[5]='387493420DA,93RE'

For a given $s, the function should return an array, following the constraints noted above.

My approach has been to use the substr function, and extract a string up to a 16 offset, from an updated position index. Can it be done in a better way?

Upvotes: 3

Views: 104

Answers (2)

Borodin
Borodin

Reputation: 126722

This is very simple using a global /g regular expression match.

This program demonstrates. The regex pattern looks for as many characters as possible up to a maximum of sixteen that must be followed by a comma or the end of the string.

However, my first thought was the same as RobEarl's comment - why not just put one field from the string into each element of the array? Is there really a need to pack more than one into an element just because it is possible?

use strict;
use warnings;
use 5.010;

my $s = '90320,328923,SKJS32767,DSIKUDIU,829EUE,AUSIUD0Q897,AJIUE98,387493420DA,93RE,AKDJ93,SADI983,90439,JADKJ84';

my @partitions;

while ( $s =~ /\G(.{0,16})(?:,|\z)/g ) {
  push @partitions, $1;
}

say for @partitions;

output

90320,328923
SKJS32767
DSIKUDIU,829EUE
AUSIUD0Q897
AJIUE98
387493420DA,93RE
AKDJ93,SADI983
90439,JADKJ84

Upvotes: 4

simbabque
simbabque

Reputation: 54323

You need to look at the length of the current string plus the current article number to determine if it is too long.

Split the long string into single articles. Concatenate the last element of the new list of strings if it's below 17 chars or push the article number as a fresh string into the list.

my $s="90320,328923,SKJS32767,DSIKUDIU,829EUE,AUSIUD0Q897,AJIUE98,387493420DA,93RE,AKDJ93,SADI983,90439,JADKJ84";
my @items = split /,/, $s;
my @strings = ( shift @items );
while ( my $item = shift @items ) {
  if ( length($strings[-1]) + length($item) > 15) { # 15 because of the comma
    push @strings, $item;
  } else {
    $strings[-1] .= ',' . $item;
  }
}

dd \@strings;

__END__
[
  "90320,328923",
  "SKJS32767",
  "DSIKUDIU,829EUE",
  "AUSIUD0Q897",
  "AJIUE98",
  "387493420DA,93RE",
  "AKDJ93,SADI983",
  "90439,JADKJ84",
]

Upvotes: 2

Related Questions