Split lines of space-delimited values to get flat array of 2nd and 3rd column values

83 Views Asked by At

I have the following data which is displaying as this

{123456  123456  123456}
{654321  654321  654321}
{123456  123456  123456}

My PHP Code:

$myarray = preg_split("/(\s|{\s)/", $data);
print_r($myarray);

The output of my array is like this:

[0] => {123456
[1] => 123456
[2] => 123456}
[3] => {654321
[4] => 654321
[5] => 654321}
[6] => {123456
[7] => 123456
[8] => 123456}

My question is, how to hide [0], [3] and [6] from the output? if you noticed, they start with a { I'm not sure if I did a mistake coding the preg_split function

Desired behavior:

if the data is like this

{1  2  3}
{4  5  6}
{7  8  9}

the desired output should be like this:

[0] => 2
[1] => 3
[2] => 5
[3] => 6
[4] => 8
[5] => 9
4

There are 4 best solutions below

6
Barmar On

Change {\s to {\d+\s so that {123456 will be a delimiter and not be included in the result.

You don't need the capture group around the regular expression.

$data = '{123456  123456  123456}
{654321  654321  654321}
{123456  123456  123456}';
$myarray = preg_split("/\s|{\d+\s/", $data);
print_r($myarray);

Output:

Array
(
    [0] => 
    [1] => 
    [2] => 123456
    [3] => 
    [4] => 123456}
    [5] => 
    [6] => 
    [7] => 654321
    [8] => 
    [9] => 654321}
    [10] => 
    [11] => 
    [12] => 123456
    [13] => 
    [14] => 123456}
)

If you also don't want } in the results, that needs to be in the regexp as well.

$myarray = preg_split("/\s+|\s*\{\d+\s*|\s*\}\s*/", $data);

You could also use a regular expression that matches a number unless it's preceded by {, using a negative lookbehind.

$data = '{1 2 3} {4 5 6} {7 8 9}';
preg_match_all('/(?<!{)\d+/', $data, $match);
$myarray = $match[0];
print_r($myarray);

Output:

Array
(
    [0] => 2
    [1] => 3
    [2] => 5
    [3] => 6
    [4] => 8
    [5] => 9
)
1
Sammitch On

Not everything needs a regular expression.

$input = <<<_E_
{123456  123456  123456}
{654321  654321  654321}
{123456  123456  123456}
_E_;

$lines = explode("\n", $input);
$lines = array_map(function($a){return trim($a, '{}');}, $lines);
$lines = array_map(function($a){return explode(' ', $a);}, $lines);
$lines = array_map('array_filter', $lines);
$items = array_merge(...$lines);

var_dump($lines, $items);

Output:

array(3) {
  [0]=>
  array(3) {
    [0]=>
    string(6) "123456"
    [2]=>
    string(6) "123456"
    [4]=>
    string(6) "123456"
  }
  [1]=>
  array(3) {
    [0]=>
    string(6) "654321"
    [2]=>
    string(6) "654321"
    [4]=>
    string(6) "654321"
  }
  [2]=>
  array(3) {
    [0]=>
    string(6) "123456"
    [2]=>
    string(6) "123456"
    [4]=>
    string(6) "123456"
  }
}
array(9) {
  [0]=>
  string(6) "123456"
  [1]=>
  string(6) "123456"
  [2]=>
  string(6) "123456"
  [3]=>
  string(6) "654321"
  [4]=>
  string(6) "654321"
  [5]=>
  string(6) "654321"
  [6]=>
  string(6) "123456"
  [7]=>
  string(6) "123456"
  [8]=>
  string(6) "123456"
}
0
mickmackusa On

Not everything needs a regular expression, but sometimes it is the most direct tool for the job.

Split the string on all characters that you don't want to keep.

Code: (Demo)

var_export(
    preg_split(
        '/ +|}\R?|{\d+/',
        $text,
        0,
        PREG_SPLIT_NO_EMPTY
    )
);
0
Jared Farrish On

Not sure if preg_split() is required, but you could do this with a match all and then gather what's found:

$foo = trim('
{555555  123456  123456}
{666666  654321  654321}
{777777  123456  123456}
');

$items = [];

if (preg_match_all('/^{[\d]{1,}  ([\d]{1,})  ([\d]{1,})}$/m', $foo, $matches)) {
    $items = array_reduce(
        array_slice($matches, 1),
        fn(array $found, array $match) => array_merge($found, $match),
        []
    );
}

var_dump($items);

Gives:

array(6) {
  [0]=>
  string(6) "123456"
  [1]=>
  string(6) "654321"
  [2]=>
  string(6) "123456"
  [3]=>
  string(6) "123456"
  [4]=>
  string(6) "654321"
  [5]=>
  string(6) "123456"
}

https://3v4l.org/n9tRk