2013-05-08 99 views
4

我想格式化电子表格(xls或xlsx),以便通过用特定颜色填充背景来格式化包含单词或以特定字符串结尾的任何单元格。使用python从Excel有条件地格式化文本字符串

例如,如果单元格包含单词“已删除”,请将其填充黑色并将文本涂成白色。 如果单元格以'.pf'结尾,则将单元格涂成红色。

我发现从几年前类似的疑问,建议如下:

import xlrd 
import xlutils.copy 

inBook = xlrd.open_workbook('input.xls', formatting_info=True) 
outBook = xlutils.copy.copy(inBook) 

def _getOutCell(outSheet, colIndex, rowIndex): 
    """ HACK: Extract the internal xlwt cell representation. """ 
    row = outSheet._Worksheet__rows.get(rowIndex) 
    if not row: return None 
    cell = row._Row__cells.get(colIndex) 
    return cell 

def setOutCell(outSheet, col, row, value): 
    """ Change cell value without changing formatting. """ 
    # HACK to retain cell style. 
    previousCell = _getOutCell(outSheet, col, row) 
    # END HACK, PART I 
    outSheet.write(row, col, value) 
    # HACK, PART II 

    if previousCell: 
     newCell = _getOutCell(outSheet, col, row) 
    if newCell: 
     newCell.xf_idx = previousCell.xf_idx 
    # END HACK 


outSheet = outBook.get_sheet(0) 
setOutCell(outSheet, 5, 5, 'Test') 
outBook.save('output.xls') 

虽然这确实从input.xls到output.xls的值复制,这​​似乎并没有转移格式(中当打开output.xls时,input.xls中的测试值不再被格式化,excel中的“管理规则”下也不存在条件格式规则。

数字值的“if”语句似乎可行,但同样,I我正在寻找一种方法来格式化包含某些字符串的单元格。谢谢!

+0

您是否尝试在原地更改文件?您可以在脚本运行之前创建文件的备份。 – Alfe 2013-05-08 19:43:53

+0

我不认为就地编辑是可能的。从我所了解的xlutils只允许您复制和修改副本。如果win32com可以做到这一点,这将是一个很酷的尝试方向,但我不知道这一点。 win32com也不是我的首选策略,因为我希望这个脚本能够在未安装excel的机器上运行(linux)。 – user2363458 2013-05-09 15:00:46

回答

2

保留原始input.xls格式,当你打开它:

from xlrd import open_workbook 

input_wb = open_workbook('input.xls', formatting_info=True) 

创建基于此模板的新工作簿:

from xlutils.copy import copy as copy_workbook 

output_wb = copy_workbook(input_wb) 

定义了一些新的单元格样式:

from xlwt import easyxf 

red_background = easyxf("pattern: pattern solid, fore_color red;") 
black_with_white_font = easyxf('pattern: pattern solid, fore_color black; font: color-index white, bold on;") 

评估并修改您的单元格:

input_ws = input_wb.sheet_by_name('StackOverflow') 
output_ws = output_wb.get_sheet(0) 

for rindex in range(0, input_ws.nrows): 
    for cindex in range(0, input_ws.ncols): 
     input_cell = input_ws.cell(rindex, cindex) 
     if input_cell.value[ input_cell.value.rfind('.'): ] == 'pf': 
      output_ws.write(rindex, cindex, input_cell.value, red_background) 
     elif input_cell.value.find('deleted') >= 0: 
      output_ws.write(rindex, cindex, input_cell.value, black_with_white_font) 
     else: 
      pass # we don't need to modify it 

保存新的工作簿

output_wb.save('output.xls') 

使用上面的例子,未经修饰细胞应该有自己的原始格式不变。

如果您需要更改单元格的内容,并想保留原来的格式(即不使用自定义easyxf实例),你可以使用这个片段:

def changeCell(worksheet, row, col, text): 
    """ Changes a worksheet cell text while preserving formatting """ 
    # Adapted from https://stackoverflow.com/a/7686555/1545769 
    previousCell = worksheet._Worksheet__rows.get(row)._Row__cells.get(col) 
    worksheet.write(row, col, text) 
    newCell = worksheet._Worksheet__rows.get(row)._Row__cells.get(col) 
    newCell.xf_idx = previousCell.xf_idx 

# ... 

changeCell(worksheet_instance, 155, 2, "New Value") 

对于比较,您可以使用字符串方法findrfind(从右侧进行搜索)。它们返回字符串中子字符串位置的索引。如果未找到子字符串,则返回-1。 Ergo,您在input_cell.value.find('deleted') >= 0之上看到以评估子字符串“已删除”是否存在。对于.pf的比较,我使用了rfind以及Python中的一个名为slicing的东西。

+0

这将导致以下错误:'回溯(最近最后一次通话): “\ stacksolution.py” 文件,14号线在 input_ws = input.sheet_by_name( '工作表Sheet1')#eval和修改细胞 AttributeError的:'builtin_function_or_method对象没有属性'sheet_by_name'' ...另外,我不清楚如何将字符串比较应用到逻辑中。例如,你的'如果input_cell.value =='逻辑在这里“'部分..这是好的,如果你说”<50 or > 60,但你如何写它的结尾与.pf“或”包含单词删除“ – user2363458 2013-05-09 12:26:15

+1

对于这个错误,当它实际上是'input_wb'(与'output_wb'相同)时,我输入了'input'作为Workbook实例名 - 确保更新这两行。在一些情况下显示条件表达式 – pztrick 2013-05-09 13:26:51

+0

这是迄今为止最好的结果,通过对input_wb和output_wb的拼写错误更正,脚本现在已成功将input.xls复制到output.xls中,其中包含所有单元格内容。格式化,如字体类型,字体大小,字体颜色它是什么**不做**,是保留条件格式或我的条件格式化规则(也许这是xlutils.copy的限制)。包含“删除”这个词的文件他们,但不是'.pf'。如果我用'.pf'使用'delete'语句,它应该有一些误报。谢谢! – user2363458 2013-05-09 14:56:31