out*_*tis 7 python openoffice-calc
为了扩展OpenOffice的功能,我在用户脚本目录(〜/ Library/Application Support/OpenOffice.org/3/user/Scripts/python /,在我的例子中)的文件中定义了一些Python宏.这些宏在Python宏管理器中可见.但是,使用单元格公式中的函数会导致"#NAME?" (OO.org错误 525).
假设我已经定义了以下函数:
def pytype(val):
return str(type(val))
Run Code Online (Sandbox Code Playgroud)
我怎样才能调用pytype单元格公式(例如=PYTYPE("string"))?
我将一些来自Authorize.net的数据导入MySQL数据库进行分析.MySQL无法将Authorize.net使用的日期和时间格式解析为一个DATETIME或多个TIMESTAMP字段,因此我试图将数据按到MySQL可以在导入之前处理的格式.OpenOffice也不会将数据识别为日期和时间,并且据我所知,OO.Org没有通用的日期解析功能.因此,我正在扩展OO.org的能力.
还有其他方法可以解决这个问题.例如,我还可以尝试使用其他列修复MySQL导入后的数据.事实上,这是我第一次做的事情; 但是,现在表中存在的数据可以应对.因此,并且因为将来还有其他任务我希望通过在公式中使用宏来实现,现在我最感兴趣的是在公式中调用Python宏.
outis - 感谢您的精彩回答。如果不是你,我现在还在写基本的宏,我会生气的!
不过我只想说几点:
invokePyFunc 的最后 2 个参数始终为空 - 只需使用:
const filename = "your_file"
Function pyFunc(func as String, args as Array)
pyFunc = invokePyFunc(filename, func, args, Array(), Array())
End Function
Run Code Online (Sandbox Code Playgroud)
多维数组很难返回。如果返回,则((1,2,3), (4,5,6))calc 会将其视为包含未知对象的行中的 2 个单元格。
这是因为 basic 和 python 对待多维数组的方式不同。
如果将此类结构返回到基本结构,则必须像data(row)(col)calc 期望data(row, col)的多维数组一样访问它。
因此,您需要使用转换器函数来返回值:
' Converts python multidimensional arrays to basic arrays.
function convPy2Basic(pyvalue)
if isarray(pyvalue) then
dim lastRow as integer
lastRow = ubound(pyvalue)
if lastRow = -1 then
' empty array
convPy2Basic = ""
else
if isarray(pyvalue(0)) then
' Multi-dimensional array
dim maxCols as integer, lastCol as integer
maxCols = ubound(pyvalue(0))
dim res(lastRow, maxCols)
for rowIndex = 0 to lastRow
lastCol = ubound(pyvalue(rowIndex))
' Expand array if needed.
if lastCol > maxCols then
maxCols = lastCol
redim preserve res(lastRow, maxCols)
end if
for colIndex = 0 to lastCol
res(rowIndex, colIndex) = pyvalue(rowIndex)(colIndex)
next colIndex
next rowIndex
convPy2Basic = res
else
' Single-dimensional array - this is supported by libreoffice
convPy2Basic = pyvalue
end if
end if
else
convPy2Basic = pyvalue
end if
end function
Function invokeScriptFunc(file AS String, lang, ext, func As String, args As Array, outIdxs As Array, outArgs As Array)
sURL = URL_Main & file & "." & ext & "$" & func & "?language=" & lang & "&location=user"
oMSP = getMasterScriptProvider()
oScript = oMSP.getScript(sURL)
invokeScriptFunc = oScript.invoke(args, outIdxs, outArgs)
end Function
Function invokePyFunc(file AS String, func As String, args As Array, outIdxs As Array, outArgs As Array)
res = invokeScriptFunc(file, "Python", "py", func, args, outIdxs, outArgs)
invokePyFunc = convPy2Basic(res)
end Function
Run Code Online (Sandbox Code Playgroud)
所以我的 python-basic 宏桥看起来像这样:
' Keep a global reference to the ScriptProvider, since this stuff may be called many times:
Global g_MasterScriptProvider as Object
' Specify location of Python script, providing cell functions:
Const URL_Main as String = "vnd.sun.star.script:"
' Converts python multidimensional arrays to basic arrays.
function convPy2Basic(pyvalue)
if isarray(pyvalue) then
dim lastRow as integer
lastRow = ubound(pyvalue)
if lastRow = -1 then
' empty array
convPy2Basic = ""
else
if isarray(pyvalue(0)) then
' Multi-dimensional array
dim maxCols as integer, lastCol as integer
maxCols = ubound(pyvalue(0))
dim res(lastRow, maxCols)
for rowIndex = 0 to lastRow
lastCol = ubound(pyvalue(rowIndex))
' Expand array if needed.
if lastCol > maxCols then
maxCols = lastCol
redim preserve res(lastRow, maxCols)
end if
for colIndex = 0 to lastCol
res(rowIndex, colIndex) = pyvalue(rowIndex)(colIndex)
next colIndex
next rowIndex
convPy2Basic = res
else
' Single-dimensional array - this is supported by libreoffice
convPy2Basic = pyvalue
end if
end if
else
convPy2Basic = pyvalue
end if
end function
Function invokeScriptFunc(file AS String, lang, ext, func As String, args As Array, outIdxs As Array, outArgs As Array)
sURL = URL_Main & file & "." & ext & "$" & func & "?language=" & lang & "&location=user"
oMSP = getMasterScriptProvider()
oScript = oMSP.getScript(sURL)
invokeScriptFunc = oScript.invoke(args, outIdxs, outArgs)
end Function
Function invokePyFunc(file AS String, func As String, args As Array, outIdxs As Array, outArgs As Array)
res = invokeScriptFunc(file, "Python", "py", func, args, outIdxs, outArgs)
invokePyFunc = convPy2Basic(res)
end Function
Function getMasterScriptProvider()
if isNull(g_MasterScriptProvider) then
oMasterScriptProviderFactory = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory")
g_MasterScriptProvider = oMasterScriptProviderFactory.createScriptProvider("")
endif
getMasterScriptProvider = g_MasterScriptProvider
End Function
const filename = "skaiciuokle"
Function pyFunc(func as String, args as Array)
pyFunc = invokePyFunc(filename, func, args, Array(), Array())
End Function
Run Code Online (Sandbox Code Playgroud)
并像这样使用:
function DamageToArmor(data, damageType as String, armorType as String, dmgPerGun as Integer, guns as Integer)
DamageToArmor = pyFunc("dmg2armor", Array(data, damageType, armorType, dmgPerGun, guns))
end function
Run Code Online (Sandbox Code Playgroud)
在旧的OO.org论坛上,(超级)用户Villeroy发布了一个如何从OO.org Basic调用Python函数的插图,然后可以在公式中使用它.关键是将com.sun.star.script.provider.MasterScriptProviderFactory服务用作桥梁.这是他的解决方案的改编,通用于在任意模块中调用任意函数:
REM Keep a global reference to the ScriptProvider, since this stuff may be called many times:
Global g_MasterScriptProvider as Object
REM Specify location of Python script, providing cell functions:
Const URL_Main as String = "vnd.sun.star.script:"
Const URL_Args as String = "?language=Python&location=user"
Function invokePyFunc(file AS String, func As String, args As Array, outIdxs As Array, outArgs As Array)
sURL = URL_Main & file & ".py$" & func & URL_Args
oMSP = getMasterScriptProvider()
On Local Error GoTo ErrorHandler
oScript = oMSP.getScript(sURL)
invokePyFunc = oScript.invoke(args, outIdxs, outArgs)
Exit Function
ErrorHandler:
Dim msg As String, toFix As String
msg = Error$
toFix = ""
If 1 = Err AND InStr(Error$, "an error occurred during file opening") Then
msg = "Couldn' open the script file."
toFix = "Make sure the 'python' folder exists in the user's Scripts folder, and that the former contains " & file & ".py."
End If
MsgBox msg & chr(13) & toFix, 16, "Error " & Err & " calling " & func
end Function
Function getMasterScriptProvider()
if isNull(g_MasterScriptProvider) then
oMasterScriptProviderFactory = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory")
g_MasterScriptProvider = oMasterScriptProviderFactory.createScriptProvider("")
endif
getMasterScriptProvider = g_MasterScriptProvider
End Function
Run Code Online (Sandbox Code Playgroud)
然后,可以使用它来创建可在公式中调用的OO.org Basic函数.使用示例pytype:
Const libfile as String = "util" REM functions live in util.py
Function pytype(value)
pytype = invokePyFunc(libfile, "pytype", Array(value), Array(), Array())
End Function
Run Code Online (Sandbox Code Playgroud)
另一个可能的实现是创建一个Python加载项.但是,这是一个更重的选项,因为它需要安装OpenOffice SDK,对我来说这种方法是否适用于免费功能或仅适用于类是不明显的.