使用字符串(不是HTML)以表格格式显示对象数组。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用字符串(不是HTML)以表格格式显示对象数组。相关的知识,希望对你有一定的参考价值。
我不想使用html平板标签,因为输出将显示在一个字符串字段中。请看下面的代码片段。预期的输出应该显示为类似于一个带键的表,作为头和对象的值分别复制到头(键)。请看下图的预期输出。对我来说,这里棘手的部分是当我把长字符串作为值时,对齐方式会受到干扰。
注意:我的最终目标是节省一些字符以避免字符串字段的溢出,所以我想到了下面的表格方法。我的字符串字段只有4000个字符的长度。如果有更好的方法以字符串格式显示对象,并且对最终用户来说是可读的,那么我不介意改变格式,只要我们不浪费任何字符来使它漂亮。
var data =
"table-info":[
"Hostname":"server 756",
"Slot":"NC1",
"VLAN":"test 12",
"Port Type":"Access",
"Port":"port 12",
"Switch":"switch12"
,
"Hostname":"",
"Slot":"NI4",
"VLAN":"test 13",
"Port Type":"Tag",
"Port":"port 13",
"Switch":"switch13"
,
"Hostname":"",
"Slot":"PC2: 2",
"VLAN":"test 14",
"Port Type":"Access",
"Port":"port 14",
"Switch":"switch14"
,
"Hostname":"",
"Slot":"NI4",
"VLAN":"test 15",
"Port Type":"Tag",
"Port":"port 15",
"Switch":"switch15"
,
"Hostname":"",
"Slot":"PCI: B",
"VLAN":"test 16",
"Port Type":"Tag",
"Port":"port 16",
"Switch":"switch16"
,
"Hostname":"",
"Slot":"PI3: A",
"VLAN":"test 17",
"Port Type":"Tag",
"Port":"port 17",
"Switch":"switch17"
,
"Hostname":"server 757",
"Slot":"NC1",
"VLAN":"test 12",
"Port Type":"Access",
"Port":"port 18",
"Switch":"switch18"
,
"Hostname":"",
"Slot":"NC4",
"VLAN":"test 13",
"Port Type":"Tag",
"Port":"port 19",
"Switch":"switch19"
,
"Hostname":"",
"Slot":"PCI2: 2",
"VLAN":"test 14",
"Port Type":"Access",
"Port":"port 20",
"Switch":"switch20"
,
"Hostname":"",
"Slot":"NI4",
"VLAN":"test 15",
"Port Type":"Tag",
"Port":"port 21",
"Switch":"switch21"
]
;
var tableInfo = data['table-info'],
headers = Object.keys(tableInfo[0]),
tableInfoLen = tableInfo.length,
headersLen = headers.length;
var result = headers.join('\t');
for (var i = 0; i < tableInfoLen; i++)
result += '\n';
for (var j = 0; j < headersLen; j++ )
if (tableInfo[i][headers[j]] == '')
result += tableInfo[i][headers[j]] + '\t'+'\t';
else
result += tableInfo[i][headers[j]] + '\t';
console.log(result);
通过使用下面的代码段,我实现了图中所示的预期输出。有一个额外的函数(padding),它可以根据给定字符串的长度添加空格,但是字符又被吃掉了,这不是我想要的。
var data =
"table-info":[
"Hostname":"server 756",
"Slot":"NC1",
"VLAN":"test 12",
"Port Type":"Access",
"Port":"port 12",
"Switch":"switch12"
,
"Hostname":"",
"Slot":"NI4",
"VLAN":"test 13",
"Port Type":"Tag",
"Port":"port 13",
"Switch":"switch13"
,
"Hostname":"",
"Slot":"PC2: 2",
"VLAN":"test 14",
"Port Type":"Access",
"Port":"port 14",
"Switch":"switch14"
,
"Hostname":"",
"Slot":"NI4",
"VLAN":"test 15",
"Port Type":"Tag",
"Port":"port 15",
"Switch":"switch15"
,
"Hostname":"",
"Slot":"PCI: B",
"VLAN":"test 16",
"Port Type":"Tag",
"Port":"port 16",
"Switch":"switch16"
,
"Hostname":"",
"Slot":"PI3: A",
"VLAN":"test 17",
"Port Type":"Tag",
"Port":"port 17",
"Switch":"switch17"
,
"Hostname":"server 757",
"Slot":"NC1",
"VLAN":"test 12",
"Port Type":"Access",
"Port":"port 18",
"Switch":"switch18"
,
"Hostname":"",
"Slot":"NC4",
"VLAN":"test 13",
"Port Type":"Tag",
"Port":"port 19",
"Switch":"switch19"
,
"Hostname":"",
"Slot":"PCI2: 2",
"VLAN":"test 14",
"Port Type":"Access",
"Port":"port 20",
"Switch":"switch20"
,
"Hostname":"",
"Slot":"NI4",
"VLAN":"test 15",
"Port Type":"Tag",
"Port":"port 21",
"Switch":"switch21"
]
;
String.prototype.padding = function(n, c)
var val = this.valueOf();
if ( Math.abs(n) <= val.length )
return val;
var m = Math.max((Math.abs(n) - this.length) || 0, 0);
var pad = Array(m + 1).join(String(c || ' ').charAt(0));
//console.log(pad);
return (n < 0) ? pad + val : val + pad;
;
var tableInfo = data['table-info'],
headers = Object.keys(tableInfo[0]),
tableInfoLen = tableInfo.length
headersLen = headers.length;
var result = '';
for (var k = 0; k < headers.length; k++ )
result += headers[k].padding(15)+'\t';
for (var i = 0; i < tableInfoLen; i++)
result += '\n';
for (var j = 0; j < headersLen; j++ )
if (tableInfo[i][headers[j]] == '')
result += tableInfo[i][headers[j]].padding(15)+ '\t';
else
result += tableInfo[i][headers[j]].padding(15) + '\t';
console.log(result);
答案
在建立表格之前,你需要测量所有将要显示的文本。
我还添加了一个文本调整枚举,这样你就可以对标题栏进行居中调整。
更新
- 动态地给每一行添加了一个索引字段,以显示数字的自动调整。
- 将众多功能转换为结构良好的ES6类。
- 创建了一个单独的测量列宽的方法,并保护了对未定义值的格式化。
- 增加了截断支持
好了,我就不说了,但你可以看到,它的可扩展性很强。
const main = () =>
let jsonData = getJson()['table-info'].map((item, index) =>
return Index : (index + 1), ...item ; // Add index to front
);
let table = new TableFormater(
scanAll : true, // We would miss some fields without it
spacer: ' | ', // Divide the columns with a pipe
columns:
'Port Type' :
align: TextAlignment.CENTER
,
'ExtraLongKeyAlsoTruncated' :
limit: 6 // Limit the number of characters
).fromJson(jsonData);
console.log(table);
;
/*
* @description An enum representing text alignment
*/
const TextAlignment = Object.freeze(
LEFT : Symbol("LEFT"),
RIGHT : Symbol("RIGHT"),
CENTER : Symbol("CENTER")
);
/*
* @description A class used for converting data into text tables
*/
class TableFormater
constructor(options)
this.opts = Object.assign(, TableFormater.DEFAULT_OPTIONS, options);
/* @public */
fromJson(json)
const fields = this.__gatherFields(json, this.opts.scanAll),
colWidths = this.__measureColumns(json, fields);
return [
fields.map((field, index) =>
return this.__format(field, field, index, colWidths,
align: TextAlignment.CENTER // Force headers to be centered
);
).join(this.opts.spacer),
json.map(record =>
return fields.map((field, index) =>
return this.__format(record[field], field, index, colWidths);
).join(this.opts.spacer);
).join('\n')
].join('\n');
/* @private */
__format(value, field, index, colWidths, overrides)
return this.__alignContent(value,
Object.assign(this.__generateMetaData(field, index, colWidths),
overrides || ));
/* @private */
__alignContent(content, metadata)
let isNumeric = !isNaN(content);
content = ('' + (content || '')).trim();
if (content.length === 0)
return content.padEnd(metadata.maxWidth); // If empty, pad away!
if (metadata.limit !== -1 && content.length > metadata.limit)
content = content.substring(0, metadata.limit - 1) + '…';
if (content.length === metadata.maxWidth)
return content; // Optimization
let alignment = metadata.align || TextAlignment.LEFT;
if (isNumeric && metadata.align == null)
alignment = TextAlignment.RIGHT;
switch (alignment)
case TextAlignment.RIGHT:
return content.padStart(metadata.maxWidth);
case TextAlignment.CENTER:
let diff = metadata.maxWidth - content.length;
let offset = Math.floor(metadata.maxWidth - (diff / 2));
return content.padStart(offset).padEnd(metadata.maxWidth);
case TextAlignment.LEFT:
default:
return content.padEnd(metadata.maxWidth);
/* @private */
__generateMetaData(field, index, colWidths)
return Object.assign(
maxWidth: colWidths[index],
limit: -1,
field: field
, this.opts.columns[field]);
/* @private */
__gatherFields(data, scanAllRecords)
return scanAllRecords
? [...new Set(data.flatMap(record => Object.keys(record)))]
: Object.keys(data[0]);
/* @private */
__measureColumns(data, fields)
let colWidths = fields.map(field => this.__measureValue(field, field));
data.forEach(item =>
fields.forEach((field, index) =>
colWidths[index] = Math.max(colWidths[index],
this.__measureValue(item[field], field));
);
);
return colWidths;
/* @private */
__measureValue(value, field)
if (value == null) return 0;
value = ('' + value).trim();
let column = this.opts.columns[field] || ;
return column.limit !== -1 && value.length > column.limit
? column.limit : value.length;
/* @static */
TableFormater.DEFAULT_OPTIONS =
columnSpacer : ' ',
columns : ,
scanAll : false
;
const getJson = () =>
return
"table-info": [
"Hostname": "server 756",
"Slot": "NC1",
"VLAN": "test 12",
"Port Type": "Access",
"Port": "port 12",
"Switch": "switch12"
,
"Slot": "NI4",
"VLAN": "test 13",
"Port Type": "Tag",
"Port": "port 13",
"Switch": "switch13"
,
"Slot": "PC2: 2",
"VLAN": "test 14",
"Port Type": "Access",
"Port": "port 14",
"Switch": "switch14",
// This is to demonstrate 'scanAll' and 'limit'
"ExtraLongKeyAlsoTruncated": "I will be truncated!"
,
"Slot": "NI4",
"VLAN": "test 15",
"Port Type": "Tag",
"Port": "port 15",
"Switch": "switch15"
,
"Slot": "PCI: B",
"VLAN": "test 16",
"Port Type": "Tag",
"Port": "port 16",
"Switch": "switch16"
,
"Slot": "PI3: A",
"VLAN": "test 17",
"Port Type": "Tag",
"Port": "port 17",
"Switch": "switch17"
,
"Hostname": "server 757",
"Slot": "NC1",
"VLAN": "test 12",
"Port Type": "Access",
"Port": "port 18",
"Switch": "switch18"
,
"Slot": "NC4",
"VLAN": "test 13",
"Port Type": "Tag",
"Port": "port 19",
"Switch": "switch19"
,
"Slot": "PCI2: 2",
"VLAN": "test 14",
"Port Type": "Access",
"Port": "port 20",
"Switch": "switch20"
,
"Slot": "NI4",
"VLAN": "test 15",
"Port Type": "Tag",
"Port": "port 21",
"Switch": "switch21"
]
;
main();
.as-console-wrapper
top: 0;
max-height: 100% !important;
.as-console-wrapper .as-console-row-code,
.as-console-wrapper .as-console-row:after
font-size: 0.8em;
以上是关于使用字符串(不是HTML)以表格格式显示对象数组。的主要内容,如果未能解决你的问题,请参考以下文章