11

I am looking for ways to split a string into an array, sort of str_split(), where the chunk sizes are dictated by an array.

I could do that by looping through the string with a bunch of substr() calls, but that looks neither elegant nor efficient. Is there a function that accept a string and an array, like (1, 18, 32, 41, 108, 125, 137, 152, 161), and yields an array of appropriately chopped string pieces?

Explode is inappropriate because the chunks are delimited by varying numbers of white spaces.

4
  • Did you check php explode() function? Commented Jul 8, 2012 at 9:57
  • Jirka: explode will not do, because of the above (my edit) Commented Jul 8, 2012 at 12:35
  • An example for this is anything from the cms.gov website such as icd10 codes or NCCI codes. They are all fixed length columns of data. I assume because the government is stuck in 1940s and hasn't heard about the invention of the CSV format let alone xml or json. cms.gov/Medicare/Coding/ICD10/2019-ICD-10-PCS.html Commented Jan 24, 2019 at 22:51
  • 1
    @dan that hyperlink is dead. This question would be clearer with a minimal reproducible example. Commented Mar 4 at 6:48

5 Answers 5

11

There is nothing in PHP that will do that for you (it's a bit specific). So as radashk just siad, you just have to write a function

function getParts($string, $positions){
    $parts = array();

    foreach ($positions as $position){
        $parts[] = substr($string, 0, $position);
        $string = substr($string, $position);
    }

    return $parts;
}

Something like that. You can then use it wherever you like, so it's clean:

$parts = getParts('some string', array(1, ... 161));

If you really wanted to, you could implode it into a regular expression:

^.{1}.{18} <lots more> .{161}$

would match what you wanted.

Sign up to request clarification or add additional context in comments.

Comments

6

I would use unpack():

$str = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890....";
$array = unpack("a1first/a26second/a10third/a*rest",$str);
print_r($array);

This returns:

Array
(
    [first] => ?
    [second] => ABCDEFGHIJKLMNOPQRSTUVWXYZ
    [third] => 1234567890
    [rest] => ....
)

1 Comment

This worked beautify for the QPP fixed length columns formats. I used A instead of a as it was space separated but thanks so much. This is the best answer I think.
3

Just for future references the regular expressions method @jay suggested goes like this:

 $regex="/(.{1})(.{18})(.{32})(.{41})(.{108})(.{125})(.{137})(.{152})(.{161})/";
 preg_match($regex,$myfixedlengthstring,$arr);

where $myfixedlengthstring is the target string and $arr gives you the result

Comments

1

A slightly more flexible variant, useful to parse ASCII tables with fixed-length records:

function ParseIrregularString  ($string, $lengths)
{ 
$parts = array(); 

foreach ($lengths as $StringKey => $position)
    { 
    $parts[$StringKey] = substr($string, 0, $position); 
    $string = substr($string, $position); 
    } 

return $parts; 
} 

Submitting the following:

$string = "abcdefghiklmnopqrstuvz";
$lengths = array ("field1"=>4, "field2"=>3, "field3"=>5, "field4"=>2);
print_r (ParseIrregularString ($string, $lengths));

returns:

Array ( [field1] => abcd [field2] => efg [field3] => hiklm [field4] => no )

Comments

0

A couple of earlier answers suggested a regex solution to parse the strings into an array of substrings, but never actually scripted the approach to convert the array to a regex. The following will declare a dynamic number of optional capture groups (in case the input string isn't long enough to satisfy all capture groups). array_shift() is used to remove the unneeded fullstring match from the output array. Demo

$string = '012345678901234567890123456789012345678901234567890123456789';
$splitAtPoints = [1, 18, 32, 41, 108, 125, 137, 152, 161];

preg_match(
    sprintf(
        '/%s/us',
        implode(
            array_map(
                fn($quantifier) => "(.{{$quantifier}})?",
                $splitAtPoints
            )
        )
    ),
    $string,
    $match
);
array_shift($match);
var_export($match);
array (
  0 => '0',
  1 => '123456789012345678',
  2 => '90123456789012345678901234567890',
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.