【问题标题】:Reading sub/superscript from Excel file using Python pandas使用 Python pandas 从 Excel 文件中读取子/上标
【发布时间】:2018-05-15 01:22:57
【问题描述】:

我正在尝试从 Excel 文件中读取格式化文本。它由一系列反应组成,有的反应物有下标,有的有上标。我正在努力区分上标和下标。

例如,假设一个反应物是:

O<sub>2</sub><sup>+</sup>

我想和

区别开来
O<sup>2+</sup>

这里有一个相关的问题: Usage of unicode() and encode() functions in Python

由此,我想也许我应该将字符串转换为 unicode,但 pandas 似乎根本不读取上标/下标。

【问题讨论】:

  • 那么,单元格内的文本是使用下标和上标字体选项格式化的吗?
  • 是的,没错
  • 应该是O₂⁺O²⁺
  • 是的...我修好了

标签: python excel pandas unicode


【解决方案1】:

Pandas 使用 xlrd 读取 Excel 文件,不幸的是 xlrd 不解析单元格中使用的格式。

openpyxl 包可以处理字符串格式,但仅适用于较旧的 .xls 格式。您可能需要编写一个查看底层 XML 数据的自定义解析器。

.xlsx 文件只是一个包含 xml 文件集合的 zip 存档。你需要看的两个是

  • file.xlsx/xl/sharedStrings.xml
  • file.xlsx/xl/worksheets/sheet1.xml(或您的工作表名称)

第一个文件包含字符串及其格式。第二个文件包含工作表中的单元格以及它们引用的字符串。这些字符串是按它们在 sharedStrings.xml 中的顺序引用的。

这是一个示例 excel 表的屏幕截图:

示例 sharedStrings.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="3" uniqueCount="3">
  <si>
    <r>
      <t>O</t>
    </r>
    <r>
      <rPr>
        <vertAlign val="subscript"/><sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
      </rPr>
      <t>2</t>
    </r>
    <r>
      <rPr>
        <vertAlign val="superscript"/><sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
      </rPr>
      <t>+</t>
    </r>
  </si>
  <si>
    <r>
      <t>H</t>
    </r>
    <r>
      <rPr>
        <vertAlign val="subscript"/><sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
      </rPr>
      <t>2</t>
    </r>
    <r>
      <rPr>
        <sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
      </rPr>
      <t>O</t>
    </r>
  </si>
  <si>
    <r>
      <t>O</t>
    </r>
    <r>
      <rPr>
        <vertAlign val="superscript"/><sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
      </rPr>
      <t>2+</t>
    </r>
  </si>
</sst>

每个&lt;si&gt; 元素都是一组文本。 &lt;r&gt; 元素是一组字符和格式。 &lt;t&gt; 元素是实际字符,前面的 &lt;rPr&gt; 元素是样式/格式。可以区分&lt;vertAlign&gt;元素中出现的上标和下标。

sheet1.xml 示例:

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac">
  <dimension ref="A1:A3" />
  <sheetViews>
    <sheetView tabSelected="1" workbookViewId="0">
      <selection activeCell="A4" sqref="A4" />
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25" />
  <sheetData>
    <row r="1" spans="1:1" ht="18.75" x14ac:dyDescent="0.35">
      <c r="A1" t="s">
        <v>0</v>
      </c>
    </row>
    <row r="2" spans="1:1" ht="18" x14ac:dyDescent="0.35">
      <c r="A2" t="s">
        <v>1</v>
      </c>
    </row>
    <row r="3" spans="1:1" ht="17.25" x14ac:dyDescent="0.25">
      <c r="A3" t="s">
        <v>2</v>
      </c>
    </row>
  </sheetData>
  <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3" />
  <pageSetup orientation="portrait" r:id="rId1" />
</worksheet>

单元格元素&lt;c&gt; 包含在&lt;row&gt; 元素中。 &lt;v&gt; 的值是对共享字符串的顺序/索引的引用。所以单元格A1 的值是第0 个sharedString,它是一个0,后跟一个下标2,后跟一个上标+。:

<si>
<r>
  <t>O</t>
</r>
<r>
  <rPr>
    <vertAlign val="subscript"/><sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
  </rPr>
  <t>2</t>
</r>
<r>
  <rPr>
    <vertAlign val="superscript"/><sz val="11"/><color theme="1"/><rFont val="Calibri"/><family val="2"/><scheme val="minor" />
  </rPr>
  <t>+</t>
</r>
</si>

要开始解析 Excel 文件,您可以使用:

import zipfile
from lxml import etree

z = zipfile.ZipFile('file.xlsx')

with z.open('xl/sharedStrings.xml') as fp:
    ss = etree.fromstring(fp.read())

with z.open('xl/worksheets/sheet1.xml') as fp:
    sh1 = etree.fromstring(fp.read())

z.close()

# get the namespaces
ssns = ss.nsmap
if None in ssns:
    ssns['none'] = ssns.pop(None)

sh1ns = sh1.nsmap
if None in sh1ns:
    sh1ns['none'] = sh1ns.pop(None)

text_list = ss.xpath('//none:si', namespaces=ssns)
cell_list = sh1.xpath('//none:c', namespaces=sh1ns)

您必须编写一个解析器来将格式转换为您想要的格式。

【讨论】:

  • 将文件另存为'xls'并使用openpyxl会更容易吗?
  • 实际上我这样做时遇到错误,它说 openpyxl 不支持 xls 格式
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-14
相关资源
最近更新 更多