7

I have a script that pulls data out of an excel spreadsheet using the xlrd module, specifically the row_values() method. It appears to do a great job, except for where "#N/A" has been auto-generated by previous VLookups, in which case xlrd gets "#N/A" as integer 42.

I had a look at string formatting methods but couldn't see how that was the issue.

Apart from having a script that has discovered the meaning of life (42), can anyone suggest what the issue may be?

Cheers

Note: The sheet no longer has the Vlookups in it, all values have been copied from other sheets, everything is plain values, no formulas.

1
  • 1
    Wild guess: the numeric code for the Excel #N/A error value is 2042. I know nothing about xlrd, but perhaps that helps. (I'd rather believe your script is thinking deep thoughts, though...)
    – jtolle
    Commented Feb 8, 2011 at 1:51

4 Answers 4

11

I found this useful. Thanks to John's initial help.

def xls_proc_text(cell, value_proc=None, text_proc=None):
    """Converts the given cell to appropriate text."""
    """The proc will come in only when the given is value or text."""
    ttype = cell.ctype
    if ttype == xlrd.XL_CELL_EMPTY or ttype == xlrd.XL_CELL_TEXT or ttype == xlrd.XL_CELL_BLANK:
        if text_proc is None:
            return cell.value
        else:
            return text_proc(cell.value)
    if ttype == xlrd.XL_CELL_NUMBER or ttype == xlrd.XL_CELL_DATE or ttype == xlrd.XL_CELL_BOOLEAN:
        if value_proc is None:
            return str(cell.value)
        else:
            return str(value_proc(cell.value))
    if cell.ctype == xlrd.XL_CELL_ERROR:
        # Apply no proc on this.
        return xlrd.error_text_from_code[cell.value]
5

xlrd docs on the web (or on your computer; open the docs in your browser and do Ctrl-F #N/A) give you the conversion table from Excel internal codes to text.

It might be of use to look at the sheet.row_types() method, and the Cell class docs which give you the cross-reference between type numbers as returned by sheet.row_types() and others. Note that it is generally more efficient to test for those type numbers than it is to use isinstance() on the values, AND there is no ambiguity using type numbers.

1
  • The links are no long valid to make this a useful answer.
    – dsh
    Commented Oct 8, 2020 at 15:38
5

As Andrew listed if you have error in the cell, xlrd writes the code of the error, which you can see here:

0x00: '#NULL!',  # Intersection of two cell ranges is empty
0x07: '#DIV/0!', # Division by zero
0x0F: '#VALUE!', # Wrong type of operand
0x17: '#REF!',   # Illegal or deleted cell reference
0x1D: '#NAME?',  # Wrong function or range name
0x24: '#NUM!',   # Value range overflow
0x2A: '#N/A',    # Argument or function not available

Converting code 0x2A from hex to dec you can get that 42 value. To avoid that you can use something like this in your code:

for rownum in xrange(sh.nrows):
    wr.writerow(['#N/A' if col.ctype == xlrd.XL_CELL_ERROR else col.value for col in sh.row(rownum)])
1
  • I have simplified the solution, Thanks to everyone above. You can Identify Error cell based on cell type.
  • The data we have is ctype of #N/A
  • value = 42 (instead of #N/A)
  • ctype will be 5

Simple solution might be Identify Error cell and put 'None' instead of 42

textType = sheet.cell(r,0).ctype #Get the type of the cell

        if textType == 5:
            text = None
        else:
            text = sheet.cell(r, 0).value

XLRD Documentation:

You can identify the all the other type based on below documentation

XL_CELL_ERROR 5 int representing internal Excel codes; for a text representation, refer to the supplied dictionary error_text_from_code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.