在 SheetJS 中获取列名数组

Getting an array of column names at SheetJS

本文关键字:数组 获取 SheetJS      更新时间:2023-09-26

我正在尝试将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/

JavaScript 中的字母数字转换

以下是受PHP解决方案启发的字母数字转换的一些不同看法。这是一个基本的最小示例,零错误检查只是为了完成工作。

我们将需要两个辅助函数进行转换。字母的字符代码已经在 Unicode 表中按字母顺序排列,因此我们只需要在转换时添加或删除偏移量。

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 来测试("重播"按钮在这里的行为不符合预期)结果,所以代码量有点大。

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>

此代码将为您提供工作簿中所有工作表的列标题名称。

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

这就是我使用 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
        }
    }
 }

在 xlsx v0.16.9 中执行以下操作

const workbookHeaders = xlsx.readFile(filePath, { sheetRows: 1 });
const columnsArray = xlsx.utils.sheet_to_json(workbookHeaders.Sheets[sheetName], { header: 1 })[0];

传递工作表,函数返回列名数组:

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 问题中采用的解决方案

更多信息:如果您想了解更多关于一般结构的信息,请查看官方链接

如果我

答对了,任务是为["A1:DD38"]之类的范围扩展Excel列名称范围。

该范围定义从 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的情况。

这是带有工作示例的 jsfiddle。

这是一种使用 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"]

谢谢你的函数numToAlpha(num)。

解决如何迭代列对我来说很有用。