0

given following text

bond0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
eth0: 11329920252 12554462    0    0    0     0          0      3561 13072970332 12899522    0    0    0     0       0          0

I need to capture columns values. I thought something about these lines:

Regex: `(\w+):(?:\s+(\d+))+`
Php: `preg_match_all('/(\w+):(?:\s+(\d+))+/sim', $data, $regs)

But unfortunately it captures only first column.

Array
(
    [0] => Array
        (
            [0] => dummy0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
            [1] => bond0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
            [2] => eth0: 11329920252 12554462    0    0    0     0          0      3561 13072970332 12899522    0    0    0     0       0          0
            [3] => ip6tnl0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
            [4] => lo: 51675995  100695    0    0    0     0          0         0 51675995  100695    0    0    0     0       0          0
            [5] => sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
            [6] => tunl0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
        )

    [1] => Array
        (
            [0] => 0
            [1] => 0
            [2] => 0
            [3] => 0
            [4] => 0
            [5] => 0
            [6] => 0
        )

)

Any suggestion? Thanks `

====EDIT==== Just to be clear: i know that i could preg_match searching for \d+ values or split the whole string in lines and run explode on the each line, but I'm interested in regex solution where I have first column as first member of resulting array(actualy forgot to put capturing braces in the first draft of question), and following columns with data, every line putted in it's dedicated array...

12
  • Using explode() here would also be a viable solution. Commented Aug 25, 2013 at 14:44
  • $array = explode($var,"\t"); would do it for you Commented Aug 25, 2013 at 14:46
  • I would prefer not to use explode, for the reasons I've written in question update. Thx anyway. Commented Aug 25, 2013 at 14:56
  • i'll add my solution in a comment incase you didn't find the preg_match solution: <?php $val = "bond0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 eth0: 11329920252 12554462 0 0 0 0 0 3561 13072970332 12899522 0 0 0 0 0 0"; $arr1 = explode("\n",$val); foreach ($arr1 as $key => $value) { $exp = explode(":",$value); $ex = preg_replace('/\s+/', ' ',trim($exp[1])); $arr[$exp[0]] = explode(" ",$ex); } var_dump($arr); ?> Commented Aug 25, 2013 at 15:05
  • Is the number of columns per row fixed? If not, you are asking for a variable number of captures, and only .NET can do that. Commented Aug 25, 2013 at 15:05

4 Answers 4

1

Why use preg_match or preg_match_all at all?

$results = array();
foreach (preg_split("/\r\n|\r|\n/", $data) as $line)
{
    list($key, $values) = explode(":", $line);
    $results[$key] = preg_split("/\s/", trim($values));
}

This should work as long as there is no more than one : on every line. Seems to me like it's the shortest and fastest way to write this too.

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

1 Comment

Not what I wanted (and it seems that it's not possible to do otherwise), but I'm marking this answer as the most elegant.
0

Here you go:

$data = explode("\n", $data);
$out = array();
foreach ($data as $d) {
    preg_match_all('/\s(\d+)/', $d, $matches);

Puts $matches[0] equal to an array of matches. You then want to add it to the array of rows:

    $out[] = $matches[0];
}

You now have an jagged array of lines and columns. So, to reference line two column four, you can go to $out[1][3].

8 Comments

Why the brackets around the space?
Ah, not needed. Removed.
array_map( 'trim', $matches[0] ) is better :)
It's smaller, but performance takes a hit from it. Foreach is faster and a bit more flexible.
/\s(\d+)/, will get the same results without needing to do a trim
|
0

I know that you are looking for preg_match solution but this is in case you didn't find any usefull answer

<?php
$val = "bond0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
eth0: 11329920252 12554462    0    0    0     0          0      3561 13072970332 12899522    0    0    0     0       0          0";
$arr1 = explode("\n",$val);
foreach ($arr1 as $value) {
    $exp = explode(":",$value);
    $ex = preg_replace('/\s+/', ' ',trim($exp[1]));
    $arr[$exp[0]] = explode(" ",$ex);
}
var_dump($arr);
?>

results:

array (size=2)
  'bond0' => 
    array (size=17)
      0 => string '' (length=0)
      1 => string '0' (length=1)
      2 => string '0' (length=1)
      3 => string '0' (length=1)
      4 => string '0' (length=1)
      5 => string '0' (length=1)
      6 => string '0' (length=1)
      7 => string '0' (length=1)
      8 => string '0' (length=1)
      9 => string '0' (length=1)
      10 => string '0' (length=1)
      11 => string '0' (length=1)
      12 => string '0' (length=1)
      13 => string '0' (length=1)
      14 => string '0' (length=1)
      15 => string '0' (length=1)
      16 => string '0' (length=1)
  'eth0' => 
    array (size=17)
      0 => string '' (length=0)
      1 => string '11329920252' (length=11)
      2 => string '12554462' (length=8)
      3 => string '0' (length=1)
      4 => string '0' (length=1)
      5 => string '0' (length=1)
      6 => string '0' (length=1)
      7 => string '0' (length=1)
      8 => string '3561' (length=4)
      9 => string '13072970332' (length=11)
      10 => string '12899522' (length=8)
      11 => string '0' (length=1)
      12 => string '0' (length=1)
      13 => string '0' (length=1)
      14 => string '0' (length=1)
      15 => string '0' (length=1)
      16 => string '0' (length=1)

Comments

0

You can do it like this:

$subject = <<<LOD
dummy0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
bond0:  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth0: 11329920252 12554462 0 0 0 0 0 3561 13072970332 12899522 0 0 0 0 0 0
ip6tnl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
lo: 51675995 100695 0 0 0 0 0 0 51675995 100695 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
tunl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
LOD;

$pattern = '~^(?<item>\w+):|\G\h+(?<value>\d+)~m';
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
$i=-1;
foreach($matches as $match) {
    if (isset($match['value']))
        $result[$i]['values'][] = $match['value'];
    else {
        $i++;
        $result[$i]['item'] = $match['item']; }
}
print_r($result);

You will obtain the format you describe in your EDIT.

Pattern details:

~               # pattern delimiter
^               # anchor for the line start (in multiline mode)
(?<item>\w+)    # named capture "item"
:       
|               # OR
\G              # force the match to be contigous from precedent
\h+             #
(?<value>\d+)   # named capture "value"
~m              # pattern delimiter, m modifier for multiline mode

2 Comments

That's an incredibly bulky way to do it.
@ConnorPeet: Not so "bulky" as you think, since the pattern is apply only once.

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.