如何在PHP中输出简单的ascii表?

问题描述 投票:0回答:8

我有一些数据,例如:

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
        )

)

我想产生如下输出:

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

在 PHP 中实现此目的最简单的方法是什么?我想避免使用库来完成如此简单的任务。

php ascii tabular
8个回答
11
投票

使用

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!
}

这使用了 10 个填充空间。正如 BoltClock 所说,您可能需要先检查最长字符串的长度,否则您的桌子将被长字符串顶住。


7
投票

另一个库具有自动列宽。

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

5
投票

我知道这个问题很老了,但它出现在我的谷歌搜索中,也许它对某人有帮助。

还有另一个 Stackoverflow 问题,有很好的答案,尤其是 这个问题,它指向一个名为 Zend/Text/Table 的 Zend Framework 模块。

希望有帮助。


文档介绍

Zend\Text\Table

 是一个使用装饰器动态创建基于文本的表格的组件。这对于在文本电子邮件中发送结构化数据或在 CLI 应用程序中显示表格信息很有帮助。 
Zend\Text\Table
支持多行列、列跨度和对齐方式。


基本用法

$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;
输出
┌──────────┬────────────────────┐ │Zend │Framework │ |──────────|────────────────────| │Zend │Framework │ └──────────┴────────────────────┘
    

2
投票
如果您不想使用任何外部库,这是一个可以完成这项工作的简单类

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; } }
这是如何使用它的示例,下面是终端上的结果

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); }

table on terminal


2
投票
对于任何对更通用的解决方案感兴趣的人,这是我在自己的代码中使用的一个函数来格式化表单的表格数据:

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

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

// 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); }
    

1
投票
除了拜伦·惠特洛克: 您可以使用

usort() 和回调来按最长数组值排序。 示例:

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

0
投票
我喜欢 Bryon 的答案,但我希望每一列都能感知长度,所以这就是我用纯 PHP/无包依赖项得出的结果。

// set up the data set you specified $data = [ [ 'title1' => 'largeeeerrrrr', 'title2' => 0, 'title3' => 47, 'title4' => 0 ], [ 'title1' => 'bla', 'title2' => 1, 'title3' => 0, 'title4' => 0 ], [ 'title1' => 'bla3', 'title2' => 0, 'title3' => 0, 'title4' => 0 ] ]; // parse array to make it easier to use foreach ($data as $i => $lines) { foreach ($lines as $key => $value) { $columns[$key][0] = $key; $columns[$key][] = $value; $rows[$i][] = $value; } } $rows = array_prepend($rows, array_keys($columns)); $lengths = array_values(array_map(fn($x) => max(array_map('strlen', $x)) , $columns)); // output ascii table foreach ($rows as $row) { foreach ($row as $key => $data) { $length = $lengths[$key]; $data = (is_bool($data)) ? (($data) ? 'true' : 'false') : $data; echo str_pad($data, $length, ' ', STR_PAD_RIGHT) . ' | '; } echo "\n"; }
输出(正是操作员想要的,但很容易定制):

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

0
投票
public static function arrayToTextTable(array $data): string { if (empty($data)) { return "No data available."; } // 提取列名(从第一行的键中获取) $headers = array_keys($data[0]); $headerRow = array_combine($headers, $headers); // 添加列名作为表头 array_unshift($data, $headerRow); // Calculate column widths dynamically $columnWidths = []; foreach ($data as $row) { foreach ($row as $key => $value) { $valueLength = mb_strlen((string) $value); $columnWidths[$key] = max($columnWidths[$key] ?? 0, $valueLength); } } // Add padding for aesthetics foreach ($columnWidths as &$width) { $width += 2; } // Build horizontal separator line $line = "+"; unset($width); foreach ($columnWidths as $width) { $line .= str_repeat("-", $width) . "+"; } // Build the table $output = $line . "\n"; foreach ($data as $index => $row) { $output .= "|"; foreach ($row as $key => $value) { $output .= " " . str_pad((string) $value, $columnWidths[$key] - 1) . "|"; } $output .= "\n"; if ($index === 0) { // Add header separator $output .= $line . "\n"; } } $output .= $line; return "\n\n" . preg_replace('/^/m', "\t", $output) . "\n"; }
输出如下

自动使用数组的键名作为头,这是一个命名数组

2025-01-20 00:25:02 [127.0.0.1][-][-][info][performance] LN-064 - IN20250120039020759653 - 第 2 行, 执行计划 +----+--------------+-------------------------------+------------+--------+---------------+-----------+---------+--------------+------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+--------------+-------------------------------+------------+--------+---------------+-----------+---------+--------------+------+----------+--------------------------+ | 1 | PRIMARY | <derived2> | | ALL | | | | | 1299 | 100.00 | | | 1 | UPDATE | io | | eq_ref | ID | ID | 122 | detail.IO_ID | 1 | 10.00 | Using where | | 2 | DERIVED | cdt_prd_prod_wp_day_io_detail | | index | idx_IO_ID | idx_IO_ID | 127 | | 4337 | 10.00 | Using where; Using index | | 3 | SUBQUERY | up | | ref | batchNo | batchNo | 123 | const | 2 | 2.50 | Using where | | 4 | UNION | cdt_prd_prod_wp_day_io_detail | | index | idx_IO_ID | idx_IO_ID | 127 | | 4337 | 10.00 | Using where; Using index | | 5 | SUBQUERY | up | | ref | batchNo | batchNo | 123 | const | 2 | 2.50 | Using where | | 6 | UNION | cdt_prd_prod_wp_day_io_detail | | index | idx_IO_ID | idx_IO_ID | 127 | | 4337 | 10.00 | Using where; Using index | | 7 | SUBQUERY | up | | ref | batchNo | batchNo | 123 | const | 2 | 2.50 | Using where | | | UNION RESULT | <union2,4,6> | | ALL | | | | | | | Using temporary | +----+--------------+-------------------------------+------------+--------+---------------+-----------+---------+--------------+------+----------+--------------------------+ 2025-01-20 00:25:02 [127.0.0.1][-][-][info][performance] LN-064 - IN20250120039020759653 - 第 2 行, 执行分析: SELECT trx_rows_locked, trx_rows_modified, trx_id, trx_state, trx_started, trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX; +-----------------+-------------------+------------+-----------+---------------------+---------------------+ | trx_rows_locked | trx_rows_modified | trx_id | trx_state | trx_started | trx_mysql_thread_id | +-----------------+-------------------+------------+-----------+---------------------+---------------------+ | 22382 | 32 | 3658441334 | RUNNING | 2025-01-20 00:25:02 | 443019 | +-----------------+-------------------+------------+-----------+---------------------+---------------------+ 2025-01-20 00:25:02 [127.0.0.1][-][-][info][performance] LN-064 - IN20250120039020759653 - 第 2 行, 分析完毕 2025-01-20 00:25:07 [127.0.0.1][-][-][info][performance] 360LN-064 - IN20250120039020759653 - SQL 数量 = 33,花费总时间 = 0.69 秒 2025-01-20 00:25:07 [127.0.0.1][-][-][info][performance] 360LN-064 - IN20250120039020759653 - 执行明细,打印阈值:0.04 秒, +-------+-------+----------+--------+---------------------+-------+ | index | print | duration | memory | timestamp | level | +-------+-------+----------+--------+---------------------+-------+ | 0 | Y | 0.05 | 5.31 | 2025-01-20 00:25:02 | 0 | | 1 | | 0.02 | 5.35 | 2025-01-20 00:25:02 | 0 | | 2 | | 0.02 | 5.34 | 2025-01-20 00:25:02 | 0 | | 3 | | 0.01 | 5.34 | 2025-01-20 00:25:02 | 0 | | 4 | | 0.01 | 5.36 | 2025-01-20 00:25:02 | 0 | | 5 | | 0.01 | 5.37 | 2025-01-20 00:25:02 | 0 |
    
© www.soinside.com 2019 - 2024. All rights reserved.