开发者

How to output a simple ascii table in PHP?

I have some data like:

Array
(
    [0] => Array
        (
            [a] => largeeeerrrrr
            [b] => 0
            [c] => 47
            [d] => 0
        )

    [1] => Array
        (
            [a] => bla
            [b] => 1
            [c] => 0
            [d] => 0
        )

    [2] => Array
        (
            [a] => bla3
            [b] => 0
            [c] => 0
            [d] => 0
        )

)

And 开发者_StackOverflow社区I want to produce an output like:

title1        | title2 | title3 | title4
largeeeerrrrr | 0      | 47     | 0
bla           | 1      | 0      | 0
bla3          | 0      | 0      | 0

Which is the simples way to achieve this in PHP? I'd like to avoid using a library for such simple task.


use printf

$i=0;
foreach( $itemlist as $items)
{
 foreach ($items as $key => $value)
 {
   if ($i++==0) // print header
   {
     printf("[%010s]|",   $key );
     echo "\n";
   }
   printf("[%010s]|",   $value);
 }
 echo "\n"; // don't forget the newline at the end of the row!
}

This uses 10 padding spaces. As BoltClock says, you probably want to check the length of the longest string first or your table will be jacked up on long strings.


Another library with auto column widths.

 <?php
 $renderer = new ArrayToTextTable($array);
 echo $renderer->getTable();


I know this question is very old, but it appears in my google search and maybe it helps someone.

There's another Stackoverflow question with good answers, especially this one that points to a Zend Framework module called Zend/Text/Table.

Hope it help.


Docs introduction

Zend\Text\Table is a component for creating text-based tables on the fly using decorators. This can be helpful for sending structured data in text emails, or to display table information in a CLI application. Zend\Text\Table supports multi-line columns, column spans, and alignment.


Basic usage

$table = new Zend\Text\Table\Table(['columnWidths' => [10, 20]]);

// Either simple
$table->appendRow(['Zend', 'Framework']);

// Or verbose
$row = new Zend\Text\Table\Row();

$row->appendColumn(new Zend\Text\Table\Column('Zend'));
$row->appendColumn(new Zend\Text\Table\Column('Framework'));

$table->appendRow($row);

echo $table;
Output
┌──────────┬────────────────────┐
│Zend      │Framework           │
|──────────|────────────────────|
│Zend      │Framework           │
└──────────┴────────────────────┘


If you don't want to use any external libraries, this is a simple class that does the job

class StringTools
{
  public static function convertForLog($variable) {
    if ($variable === null) {
      return 'null';
    }
    if ($variable === false) {
      return 'false';
    }
    if ($variable === true) {
      return 'true';
    }
    if (is_array($variable)) {
      return json_encode($variable);
    }
    return $variable ? $variable : "";
  }

  public static function toAsciiTable($array, $fields, $wrapLength) {
    // get max length of fields
    $fieldLengthMap = [];
    foreach ($fields as $field) {
      $fieldMaxLength = 0;
      foreach ($array as $item) {
        $value = self::convertForLog($item[$field]);
        $length = strlen($value);
        $fieldMaxLength = $length > $fieldMaxLength ? $length : $fieldMaxLength;
      }
      $fieldMaxLength = $fieldMaxLength > $wrapLength ? $wrapLength : $fieldMaxLength;
      $fieldLengthMap[$field] = $fieldMaxLength;
    }

    // create table
    $asciiTable = "";
    $totalLength = 0;
    foreach ($array as $item) {
      // prepare next line
      $valuesToLog = [];
      foreach ($fieldLengthMap as $field => $maxLength) {
        $valuesToLog[$field] = self::convertForLog($item[$field]);
      }

      // write next line
      $lineIsWrapped = true;
      while ($lineIsWrapped) {
        $lineIsWrapped = false;
        foreach ($fieldLengthMap as $field => $maxLength) {
          $valueLeft = $valuesToLog[$field];
          $valuesToLog[$field] = "";
          if (strlen($valueLeft) > $maxLength) {
            $valuesToLog[$field] = substr($valueLeft, $maxLength);
            $valueLeft = substr($valueLeft, 0, $maxLength);
            $lineIsWrapped = true;
          }
          $asciiTable .= "| {$valueLeft} " . str_repeat(" ", $maxLength - strlen($valueLeft));
        }
        $totalLength = $totalLength === 0 ? strlen($asciiTable) + 1 : $totalLength;
        $asciiTable .= "|\n";
      }
    }

    // add lines before and after
    $horizontalLine = str_repeat("-", $totalLength);
    $asciiTable = "{$horizontalLine}\n{$asciiTable}{$horizontalLine}\n";
    return $asciiTable;
  }
}

This is an example of how to use it and below is the result on the terminal

public function handle() {
  $array = [
      ["name" => "something here", "description" => "a description here to see", "value" => 3],
      ["name" => "and a boolean", "description" => "this is another thing", "value" => true],
      ["name" => "a duck and a dog", "description" => "weird stuff is happening", "value" => "truly weird"],
      ["name" => "with rogue field", "description" => "should not show it", "value" => false, "rogue" => "nie"],
      ["name" => "some kind of array", "description" => "array i tell you", "value" => [3, 4, 'banana']],
      ["name" => "can i handle null?", "description" => "let's see", "value" => null],
  ];
  $table = StringTools::toAsciiTable($array, ["name", "value", "description"], 50);
  print_r($table);
}

How to output a simple ascii table in PHP?


In addition to Byron Whitlock: You can use usort() with a callback to sort by longest array value. Example:

function lengthSort($a, $b){
    $a = strlen($a);
    $b = strlen($b);
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}


For anyone interested in a more general solution, here's a function I'm using in my own code to format tabular data of the form:

$data = [
  ['Header 1', 'Header 2'],
  ['Row1Cell1', 'Row1Cell2'],
  ['Row2Cell1', 'Row2Cell2'],
];

To get:

┌───────────────────────┐
│ Header 1  │ Header 2  │
├───────────────────────┤
│ Row1Cell1 │ Row1Cell2 │
│ Row2Cell1 │ Row2Cell2 │
└───────────────────────┘

The code:

// needed because str_pad doesn't play nice with Unicode
// https://stackoverflow.com/a/67708895/337554
// https://bugs.php.net/bug.php?id=21317
public static function pad(string $string, int $length, string $pad_string = " "): string
{
    return $string . str_repeat($pad_string, $length - mb_strlen($string));
}

public static function asciiTable(array $rows): string
{
    if (count($rows) === 0) {
        return '';
    }

    $widths = [];
    foreach ($rows as $cells) {
        foreach ($cells as $j => $cell) {
            if (($width = strlen($cell) + 2) >= ($widths[$j] ?? 0)) {
                $widths[$j] = $width;
            }
        }
    }

    $hBar = str_repeat('─', array_sum($widths) + count($widths) - 1);
    $topB = sprintf("┌%s┐", $hBar);
    $midB = sprintf("├%s┤", $hBar);
    $botB = sprintf("└%s┘", $hBar);

    $result[] = $topB;
    $fn = fn(string $c, int $w): string => self::pad(" {$c} ", $w);
    foreach ($rows as $i => $cells) {
        $result[] = sprintf("│%s│", implode('│', array_map($fn, $cells, $widths)));
        if ($i === 0) {
            $result[] = $midB;
        }
    }
    $result[] = $botB;

    return implode("\n", $result);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜