在 SheetJS 中获取列名数组
Getting an array of column names at SheetJS
我正在尝试将 Excel 电子表格 (.xlsx) 解析为 JSON。
我正在使用 SheetJS 节点包。
但是我无法实现这么简单的事情 - 如何获得与内部存储格式相同的列名?
下面是我的代码:
function _buildColumnsArray(range) {
// range = "A1:CA38"
// ...
// should return ['A', ..., 'Z', 'AA', ..., 'AZ', 'BA', ..., 'BZ', 'CA'...]
}
// --------
var workbook = XLSX.readFile(fileUrl),
sheets = workbook.Sheets,
result = {};
result.sheetNames = [];
for (var i = 0; i < workbook.SheetNames.length; i++) {
var sheet = workbook.Sheets[workbook.SheetNames[i]],
csvSheet = XLSX.utils.sheet_to_csv(sheet);
// '!ref' referring to a specific range by docs
if (sheet["!ref"]) {
var columns = _buildColumnsArray(sheet["!ref"]),
rows = _buildRowsArray(columns, csvSheet);
// build final result
result[workbook.SheetNames[i]] = {
columns: columns,
rows: rows
};
result.sheetNames.push(workbook.SheetNames[i]);
}
}
这是我目前正在尝试但效果不佳的方法:https://jsfiddle.net/t8hej9hu/
如果我答对了问题,任务是将 Excel 列名称范围扩展为范围 ["A1:DD38"].
范围定义了一个从 A 到 DD 的列和从 1 到 38 的行的块。
我们只需要得到一个扩展的列列表:
A, B, ... Z, AA, AB, ..., AZ, BA, ... BZ, ...
请注意,这行列名实际上用作数字。您从 "A" 开始,然后转到 "Z"。然后 "B" 成为第一个数字,我们在零数字中继续 "A" 到 "Z",依此类推。
所以列名实际上代表 26 进制系统中的数字,其中 0 = "A"、1 = "B" 等等。
在 javascript 中,我们有 Number().toString(radix) 方法将数字转换为具有任何给定基数的另一个数字系统,请参阅。
反向转换可以用parseInt(radix)来完成。
对于基数为 26 的系统,javascript 使用从 0 到 9 的数字,然后使用从 "a" 到 "p" 的小写字母作为其余符号。
我们可以通过简单的字符替换从 javascript 系统切换到 excel 系统("A" 到 "Z"),因为系统具有相同的基础。
所以我们的任务简化为:
- 将开始/结束列转换为十进制值
- 从头到尾迭代
- 将每个数字转换为Excel系统并添加到结果数组
更新:
不幸的是,情况并不理想,我们有 A...Z
然后 AA ... AZ
,而 A 代表零位。
所以在数字上就像有 0..9
然后 00..09
然后只有 10...19
,所以我们需要人为地模拟 00...09
的情况。
JavaScript
中的字母数字转换
受 PHP 解决方案的启发,这里有一些不同的字母数字转换。这是一个 bare-bone 最小的例子,零错误检查只是为了完成这项工作。
我们需要两个辅助函数来进行转换。字母表字母的字符代码在Unicode中已经按字母顺序table,所以我们只需要在转换时添加或删除偏移量即可。
function alphaToNum(alpha) {
var i = 0,
num = 0,
len = alpha.length;
for (; i < len; i++) {
num = num * 26 + alpha.charCodeAt(i) - 0x40;
}
return num - 1;
}
还有一个用于将数字转换为字母数字。
function numToAlpha(num) {
var alpha = '';
for (; num >= 0; num = parseInt(num / 26, 10) - 1) {
alpha = String.fromCharCode(num % 26 + 0x41) + alpha;
}
return alpha;
}
_buildColumnsArray
函数的最终版本:
function _buildColumnsArray(range) {
var i,
res = [],
rangeNum = range.split(':').map(function(val) {
return alphaToNum(val.replace(/[0-9]/g, ''));
}),
start = rangeNum[0],
end = rangeNum[1] + 1;
for (i = start; i < end ; i++) {
res.push(numToAlpha(i));
}
return res;
}
返回的数组必须与MS中的列名完全一致Excel:
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA']
这里是一个工作示例,我一直在使用 Mocha 和 Chai 测试("replay" 按钮在这里没有按预期运行)结果,所以代码量有点大。
function alphaToNum(alpha) {
var i = 0,
num = 0,
len = alpha.length;
for (; i < len; i++) {
num = num * 26 + alpha.charCodeAt(i) - 0x40;
}
return num - 1;
}
function numToAlpha(num) {
var alpha = '';
for (; num >= 0; num = parseInt(num / 26, 10) - 1) {
alpha = String.fromCharCode(num % 26 + 0x41) + alpha;
}
return alpha;
}
function _buildColumnsArray(range) {
var i,
res = [],
rangeNum = range.split(':').map(function(val) {
return alphaToNum(val.replace(/[0-9]/g, ''));
}),
start = rangeNum[0],
end = rangeNum[1] + 1;
for (i = start; i < end ; i++) {
res.push(numToAlpha(i));
}
return res;
}
mocha.setup('bdd');
chai.should();
describe('Alphabet Numbers with base 26', function() {
describe('alphaToNum', function() {
it('alphaToNum(\'A\') should be equal 0', function() {
alphaToNum('A').should.equal(0);
});
it('alphaToNum(\'HELLO\') should be equal 3752126', function() {
alphaToNum('HELLO').should.equal(3752126);
});
});
describe('numToAlpha', function() {
it('numToAlpha(3) should be equal \'D\'', function() {
numToAlpha(3).should.equal('D');
});
it('numToAlpha(1337) should be equal 3752126', function() {
numToAlpha(1337).should.equal('AYL');
});
});
describe('Alphabet Numbers range', function() {
it('_buildColumnsArray(\'B10:K10\') should be deep equal [ \'B\', \'C\', \'D\', \'E\', \'F\', \'G\' , \'H\']', function() {
_buildColumnsArray('B10:H10').should.deep.equal(['B', 'C', 'D', 'E', 'F', 'G', 'H']);
});
it('_buildColumnsArray(\'A1: CA38\') should be equal [\'A\', \'B\', \'C\', \'D\', \'E\', \'F\', \'G\', \'H\', \'I\', \'J\', \'K\', \'L\', \'M\', \'N\', \'O\', \'P\', \'Q\', \'R\', \'S\', \'T\', \'U\', \'V\', \'W\', \'X\', \'Y\', \'Z\', \'AA\', \'AB\', \'AC\', \'AD\', \'AE\', \'AF\', \'AG\', \'AH\', \'AI\', \'AJ\', \'AK\', \'AL\', \'AM\', \'AN\', \'AO\', \'AP\', \'AQ\', \'AR\', \'AS\', \'AT\', \'AU\', \'AV\', \'AW\', \'AX\', \'AY\', \'AZ\', \'BA\', \'BB\', \'BC\', \'BD\', \'BE\', \'BF\', \'BG\', \'BH\', \'BI\', \'BJ\', \'BK\', \'BL\', \'BM\', \'BN\', \'BO\', \'BP\', \'BQ\', \'BR\', \'BS\', \'BT\', \'BU\', \'BV\', \'BW\', \'BX\', \'BY\', \'BZ\', \'CA\']', function() {
_buildColumnsArray('A1:CA38').should.deep.equal(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA']);
});
});
});
mocha.run();
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.js"></script>
<div id="mocha"></div>
这就是我使用 SheetJS 的方式。
var colValues =[];
function checkCols(workbook) //your workbook variable
{
var first_sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[first_sheet_name];
var cells = Object.keys(worksheet);
for (var i = 0; i < Object.keys(cells).length; i++) {
if( cells[i].indexOf('1') > -1)
{
colValues.push(worksheet[cells[i]].v); //Contails all column names
}
}
}
此代码将为您提供工作簿中所有工作表中的列 headers 名称。
var XLSX = require('xlsx');
var workbook = XLSX.readFile('./test.xlsx');
var sheet_name_list = workbook.SheetNames;
let columnHeaders = [];
for (var sheetIndex = 0; sheetIndex < sheet_name_list.length; sheetIndex++) {
var worksheet = workbook.Sheets[sheet_name_list[sheetIndex]];
for (let key in worksheet) {
let regEx = new RegExp("^\(\w\)\(1\){1}$");
if (regEx.test(key) == true) {
columnHeaders.push(worksheet[key].v);
}
}
}
向工作表和函数returns传递一个列名数组:
get_header_row(sheet) {
let headers = [];
let range = XLSX.utils.decode_range(sheet['!ref']);
let C, R = range.s.r; /* start in the first row */
/* walk every column in the range */
for(C = range.s.c; C <= range.e.c; ++C) {
let cell = sheet[XLSX.utils.encode_cell({c:C, r:R})] /* find the cell in the first row */
let hdr = "";
if(cell && cell.t) hdr = XLSX.utils.format_cell(cell);
headers.push(hdr);
}
return headers;
}
参考:方案取自Github Issue
更多信息:如果您想了解更多关于一般结构的信息,请查看official link
在 xlsx v0.16.9 中做了以下操作
const workbookHeaders = xlsx.readFile(filePath, { sheetRows: 1 });
const columnsArray = xlsx.utils.sheet_to_json(workbookHeaders.Sheets[sheetName], { header: 1 })[0];
这是一种使用 Sheetjs 创建列数组的方法
cols: function(refstr){
return Array.from({length: XLSX.utils.decode_range(refstr).e.c + 1}, (x,i) => (XLSX.utils.encode_col(i)));
}
refstr
应该是 worksheet["!ref"]
我正在尝试将 Excel 电子表格 (.xlsx) 解析为 JSON。
我正在使用 SheetJS 节点包。
但是我无法实现这么简单的事情 - 如何获得与内部存储格式相同的列名?
下面是我的代码:
function _buildColumnsArray(range) {
// range = "A1:CA38"
// ...
// should return ['A', ..., 'Z', 'AA', ..., 'AZ', 'BA', ..., 'BZ', 'CA'...]
}
// --------
var workbook = XLSX.readFile(fileUrl),
sheets = workbook.Sheets,
result = {};
result.sheetNames = [];
for (var i = 0; i < workbook.SheetNames.length; i++) {
var sheet = workbook.Sheets[workbook.SheetNames[i]],
csvSheet = XLSX.utils.sheet_to_csv(sheet);
// '!ref' referring to a specific range by docs
if (sheet["!ref"]) {
var columns = _buildColumnsArray(sheet["!ref"]),
rows = _buildRowsArray(columns, csvSheet);
// build final result
result[workbook.SheetNames[i]] = {
columns: columns,
rows: rows
};
result.sheetNames.push(workbook.SheetNames[i]);
}
}
这是我目前正在尝试但效果不佳的方法:https://jsfiddle.net/t8hej9hu/
如果我答对了问题,任务是将 Excel 列名称范围扩展为范围 ["A1:DD38"].
范围定义了一个从 A 到 DD 的列和从 1 到 38 的行的块。 我们只需要得到一个扩展的列列表:
A, B, ... Z, AA, AB, ..., AZ, BA, ... BZ, ...
请注意,这行列名实际上用作数字。您从 "A" 开始,然后转到 "Z"。然后 "B" 成为第一个数字,我们在零数字中继续 "A" 到 "Z",依此类推。
所以列名实际上代表 26 进制系统中的数字,其中 0 = "A"、1 = "B" 等等。
在 javascript 中,我们有 Number().toString(radix) 方法将数字转换为具有任何给定基数的另一个数字系统,请参阅。
反向转换可以用parseInt(radix)来完成。
对于基数为 26 的系统,javascript 使用从 0 到 9 的数字,然后使用从 "a" 到 "p" 的小写字母作为其余符号。
我们可以通过简单的字符替换从 javascript 系统切换到 excel 系统("A" 到 "Z"),因为系统具有相同的基础。
所以我们的任务简化为:
- 将开始/结束列转换为十进制值
- 从头到尾迭代
- 将每个数字转换为Excel系统并添加到结果数组
更新:
不幸的是,情况并不理想,我们有 A...Z
然后 AA ... AZ
,而 A 代表零位。
所以在数字上就像有 0..9
然后 00..09
然后只有 10...19
,所以我们需要人为地模拟 00...09
的情况。
JavaScript
中的字母数字转换受 PHP 解决方案的启发,这里有一些不同的字母数字转换。这是一个 bare-bone 最小的例子,零错误检查只是为了完成这项工作。
我们需要两个辅助函数来进行转换。字母表字母的字符代码在Unicode中已经按字母顺序table,所以我们只需要在转换时添加或删除偏移量即可。
function alphaToNum(alpha) {
var i = 0,
num = 0,
len = alpha.length;
for (; i < len; i++) {
num = num * 26 + alpha.charCodeAt(i) - 0x40;
}
return num - 1;
}
还有一个用于将数字转换为字母数字。
function numToAlpha(num) {
var alpha = '';
for (; num >= 0; num = parseInt(num / 26, 10) - 1) {
alpha = String.fromCharCode(num % 26 + 0x41) + alpha;
}
return alpha;
}
_buildColumnsArray
函数的最终版本:
function _buildColumnsArray(range) {
var i,
res = [],
rangeNum = range.split(':').map(function(val) {
return alphaToNum(val.replace(/[0-9]/g, ''));
}),
start = rangeNum[0],
end = rangeNum[1] + 1;
for (i = start; i < end ; i++) {
res.push(numToAlpha(i));
}
return res;
}
返回的数组必须与MS中的列名完全一致Excel:
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA']
这里是一个工作示例,我一直在使用 Mocha 和 Chai 测试("replay" 按钮在这里没有按预期运行)结果,所以代码量有点大。
function alphaToNum(alpha) {
var i = 0,
num = 0,
len = alpha.length;
for (; i < len; i++) {
num = num * 26 + alpha.charCodeAt(i) - 0x40;
}
return num - 1;
}
function numToAlpha(num) {
var alpha = '';
for (; num >= 0; num = parseInt(num / 26, 10) - 1) {
alpha = String.fromCharCode(num % 26 + 0x41) + alpha;
}
return alpha;
}
function _buildColumnsArray(range) {
var i,
res = [],
rangeNum = range.split(':').map(function(val) {
return alphaToNum(val.replace(/[0-9]/g, ''));
}),
start = rangeNum[0],
end = rangeNum[1] + 1;
for (i = start; i < end ; i++) {
res.push(numToAlpha(i));
}
return res;
}
mocha.setup('bdd');
chai.should();
describe('Alphabet Numbers with base 26', function() {
describe('alphaToNum', function() {
it('alphaToNum(\'A\') should be equal 0', function() {
alphaToNum('A').should.equal(0);
});
it('alphaToNum(\'HELLO\') should be equal 3752126', function() {
alphaToNum('HELLO').should.equal(3752126);
});
});
describe('numToAlpha', function() {
it('numToAlpha(3) should be equal \'D\'', function() {
numToAlpha(3).should.equal('D');
});
it('numToAlpha(1337) should be equal 3752126', function() {
numToAlpha(1337).should.equal('AYL');
});
});
describe('Alphabet Numbers range', function() {
it('_buildColumnsArray(\'B10:K10\') should be deep equal [ \'B\', \'C\', \'D\', \'E\', \'F\', \'G\' , \'H\']', function() {
_buildColumnsArray('B10:H10').should.deep.equal(['B', 'C', 'D', 'E', 'F', 'G', 'H']);
});
it('_buildColumnsArray(\'A1: CA38\') should be equal [\'A\', \'B\', \'C\', \'D\', \'E\', \'F\', \'G\', \'H\', \'I\', \'J\', \'K\', \'L\', \'M\', \'N\', \'O\', \'P\', \'Q\', \'R\', \'S\', \'T\', \'U\', \'V\', \'W\', \'X\', \'Y\', \'Z\', \'AA\', \'AB\', \'AC\', \'AD\', \'AE\', \'AF\', \'AG\', \'AH\', \'AI\', \'AJ\', \'AK\', \'AL\', \'AM\', \'AN\', \'AO\', \'AP\', \'AQ\', \'AR\', \'AS\', \'AT\', \'AU\', \'AV\', \'AW\', \'AX\', \'AY\', \'AZ\', \'BA\', \'BB\', \'BC\', \'BD\', \'BE\', \'BF\', \'BG\', \'BH\', \'BI\', \'BJ\', \'BK\', \'BL\', \'BM\', \'BN\', \'BO\', \'BP\', \'BQ\', \'BR\', \'BS\', \'BT\', \'BU\', \'BV\', \'BW\', \'BX\', \'BY\', \'BZ\', \'CA\']', function() {
_buildColumnsArray('A1:CA38').should.deep.equal(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA']);
});
});
});
mocha.run();
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.min.js"></script>
<div id="mocha"></div>
这就是我使用 SheetJS 的方式。
var colValues =[];
function checkCols(workbook) //your workbook variable
{
var first_sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[first_sheet_name];
var cells = Object.keys(worksheet);
for (var i = 0; i < Object.keys(cells).length; i++) {
if( cells[i].indexOf('1') > -1)
{
colValues.push(worksheet[cells[i]].v); //Contails all column names
}
}
}
此代码将为您提供工作簿中所有工作表中的列 headers 名称。
var XLSX = require('xlsx');
var workbook = XLSX.readFile('./test.xlsx');
var sheet_name_list = workbook.SheetNames;
let columnHeaders = [];
for (var sheetIndex = 0; sheetIndex < sheet_name_list.length; sheetIndex++) {
var worksheet = workbook.Sheets[sheet_name_list[sheetIndex]];
for (let key in worksheet) {
let regEx = new RegExp("^\(\w\)\(1\){1}$");
if (regEx.test(key) == true) {
columnHeaders.push(worksheet[key].v);
}
}
}
向工作表和函数returns传递一个列名数组:
get_header_row(sheet) {
let headers = [];
let range = XLSX.utils.decode_range(sheet['!ref']);
let C, R = range.s.r; /* start in the first row */
/* walk every column in the range */
for(C = range.s.c; C <= range.e.c; ++C) {
let cell = sheet[XLSX.utils.encode_cell({c:C, r:R})] /* find the cell in the first row */
let hdr = "";
if(cell && cell.t) hdr = XLSX.utils.format_cell(cell);
headers.push(hdr);
}
return headers;
}
参考:方案取自Github Issue
更多信息:如果您想了解更多关于一般结构的信息,请查看official link
在 xlsx v0.16.9 中做了以下操作
const workbookHeaders = xlsx.readFile(filePath, { sheetRows: 1 });
const columnsArray = xlsx.utils.sheet_to_json(workbookHeaders.Sheets[sheetName], { header: 1 })[0];
这是一种使用 Sheetjs 创建列数组的方法
cols: function(refstr){
return Array.from({length: XLSX.utils.decode_range(refstr).e.c + 1}, (x,i) => (XLSX.utils.encode_col(i)));
}
refstr
应该是 worksheet["!ref"]