Process a BGP table, returning the tabulated data into an array
<?php
/**
* Código feito em PHP, Haters Gonna Hate! :P
*
* Brincadeiras a parte, foi a forma mais eficiente de resolver o
* problema, tenho certeza que passar a lógica pra Python pra vc vai
* ser fichinha! :P
*/
// Input de dados para exemplo
$input = 'BGP table version is 0, local router ID is 10.0.0.2
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
r RIB-failure, S Stale, R Removed
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
* 172.31.1.0/24 40.0.0.4 0 7678 7675 i
*> 10.0.0.1 0 0 7675 i
*> 172.31.2.0/24 0.0.0.0 0 32768 i
*> 172.31.3.0/24 10.0.0.1 0 7675 7677 i
* 40.0.0.4 0 7678 7677 i
* 172.31.4.0/24 10.0.0.1 0 7675 7678 i
*> 40.0.0.4 0 0 7678 i
*> 000.00.0.0/00 00.0.0.0 0 0 0 7678 0000 i
Total numberof prefixes 4';
$block = explode("\n\n", $input); // Pega só o bloco principal a ser processado
$lines = explode("\n", $block[1]); // Gera um array com uma informação por linha
$header = array_shift($lines); // Pega a primeira linha que é o header da tabela
$header = str_replace('Next Hop', 'Next_Hop', $header); // POG, admito, shame on me! XP
/**
* Aqui começa a maracutaia. Essa regex pega a primeira letra precedida de um espaço.
* Dessa forma, consigo ter um array com todos os "headers" da tabela
*/
$header = preg_split('/ [a-zA-Z]/', $header);
// No split, a primeira coluna só perdeu 1 caracter, então retiramos mais um aqui
$header[0] = substr($header[0], 0, -1);
$output = array();
$regex = array();
/**
* Aqui a gente interage com esses headers, gerando um RegEx a ser usado depois
* O "$column+1" acontece porquê a nossa regex anterior "comeu" os dois primeiros
* caracteres do nome da tabela, então temos de compensar aqui!
*/
foreach ($header as $column) {
$regex[] = '(.{' . (strlen($column)+2) . '})';
}
/**
* Aqui removemos o último elemento da array, e substituimos por (.+), pois ele
* deve seguir até o final da linha. O implode serve para transformar a array em
* uma string, sendo que neste nosso exemplo ela deve ficar assim:
*
* "/(.{3})(.{16})(.{19})(.{6})(.{6})(.{6})(.+)/"
*/
array_pop($regex);
$regex = '/' . implode($regex) . '(.+)/';
/**
* Agora vamos ao que interessa. Iteramos as linhas com os dados a serem procesados,
* aplicando a RegEx a cada linha do array. O array_shift remove o primeiro elemento
* desse array, que é a string completa, e depois aplicamos o comando trm() a todos
* os elementos, restando apenas os dados que não interessa. Se a coluna estiver
* vazia, o trim() vai deixar nosso elemento do array vazio.
*/
foreach ($lines as $line) {
preg_match_all($regex, $line, $result, PREG_SET_ORDER);
array_shift($result[0]); // remove o primeiro elemento, que é a string completa
$result = array_map('trim', $result[0]);
$output[] = $result;
}
var_dump($output);