在excel单元格中显示> 255个字符

时间:2016-04-25 20:54:20

标签: xlwings

当我的UDF返回超过255个字符串时,Excel显示#VALUE!

xlwings是0.7.1而excel是2007年,根据微软的说法,单元格中最多可包含32767个字符。

哪里可能是问题?

2 个答案:

答案 0 :(得分:2)

我可以说,Py.CallUDF(由xlwings udfs使用)返回一个2D Variant数组。

出于某种原因,似乎从纯VBA UDF返回字符串长度大于255的Variant数组会在excel中调用时导致#VALUE错误。在VBA编辑器中将监视放在阵列上会显示数据完好无损,而且没有正确传递给excel。一点点搜索返回了几个关于VBA中最大字符串长度的问题,但没有专门解决这个问题。

使用>返回字符串数组或单个字符串但是255个字符似乎工作正常。

以下是一些显示问题的纯VBA示例:

返回变体数组:

Function variant_long_string(n)
    Dim temp(0 To 0, 0 To 0) As Variant
    temp(0, 0) = String(n, "a")
    variant_long_string = temp
End Function

从Excel调用,返回(N> 255时失败):

255 aaaaaaaaaaaaa....aaaaaaaaa
256 #VALUE!

返回变体数组的元素:

Function variant_long_string_element(n)
    Dim temp(0 To 0, 0 To 0) As Variant
    temp(0, 0) = String(n, "a")
    variant_long_string_element = temp(0, 0)
End Function

从Excel调用,返回(成功N> 255):

255 aaaaaaaaaaaaa....aaaaaaaaa
256 aaaaaaaaaaaaa....aaaaaaaaaa

返回字符串数组:

Function string_long_string(n)
    Dim temp(0 To 0, 0 To 0) As String
    temp(0, 0) = String(n, "a")
    string_long_string = temp
End Function

从Excel调用,返回(成功N> 255):

255 aaaaaaaaaaaaa....aaaaaaaaa
256 aaaaaaaaaaaaa....aaaaaaaaaa

解决方法

如果你的python UDF只返回一个字符串值,如下所示:

@xw.func    
def build_long_string(n):
    res = 'a'*int(n)
    return res 

xlwings将在xlwings_udfs模块中自动生成以下VBA宏:

Function build_long_string(n)
        If TypeOf Application.Caller Is Range Then On Error GoTo failed
        build_long_string = Py.CallUDF(PyScriptPath, "build_long_string", Array(n), ThisWorkbook)
        Exit Function
failed:
        build_long_string = Err.Description
End Function

作为让您的UDF正常工作的快速补丁,请稍微更改该宏:

Function build_long_string(n)
        If TypeOf Application.Caller Is Range Then On Error GoTo failed
        temp = Py.CallUDF(PyScriptPath, "build_long_string", Array(n), ThisWorkbook)
        build_long_string = temp(0, 0)
        Exit Function
failed:
        build_long_string = Err.Description
End Function

允许字符串> gt; 255成功使其成为Excel。你可以为数组结果做类似的事情,你只需要通过循环/重新分配从temp到结果的所有值来将Variant数组转换为String数组。

答案 1 :(得分:2)

根据@ schoolie关于将2D Variant数组转换为2D String数组的建议,我在本地xlwings中修改了VBA函数生成逻辑的来源:

在udfs.generate_vba_wrapper()

取代:

vba.write('{fname} = Py.CallUDF("{module_name}", "{fname}", {args_vba}, ThisWorkbook)\n',
                    module_name=module_name,
                    fname=fname,
                    args_vba=args_vba,
                )

使用:

vba.write('r = Py.CallUDF("{module_name}", "{fname}", {args_vba}, ThisWorkbook)\n',
                                        module_name=module_name,
                                        fname=fname,
                                        args_vba=args_vba,
                                    )                    
                vba.write('ReDim strarray(UBound(r, 1), UBound(r, 2)) As String\n')
                vba.write('For i = 0 To UBound(r, 1)\n')
                vba.write('  For j = 0 To UBound(r, 2)\n')
                vba.write('    strarray(i, j) = CStr(r(i, j))\n')
                vba.write('  Next\n')
                vba.write('Next\n')
                vba.write('{fname} = strarray\n', fname=fname)

另一个选择是在执行'导入Python UDF后,在VB编辑器中修补生成的VB宏。但是,如果您重新导入,此更改将会丢失。上述代码已由@schoolie

提供