【问题标题】:Insert a function / formula in Excel from R and VBA & Apply a VBA macro from R从 R 和 VBA 在 Excel 中插入函数/公式并从 R 应用 VBA 宏
【发布时间】:2014-10-16 21:46:55
【问题描述】:

我正在寻找一种将公式/函数从 R 插入 Excel 的方法。我浏览了所有包,我能做的最好的事情是:

library(xlsx)
wb = createWorkbook(type = "xlsx")
sh = createSheet(wb, "CANFI")
cell = CellBlock(sheet = sh, startRow = 2, startColumn = 2, noRows = 1, noColumns = 1)
CB.setMatrixData(cellBlock = cell, x = as.matrix('=SUM(A1:A2)'), startRow = 1, startColumn = 1)
saveWorkbook(wb, file =  "./test.xlsx")

这给了我一个文件,公式写在单元格 SUM(A1:A2) 中,就好像它是 Excel 中的字符串一样。如果单击单元格并按 Enter,则公式会计算结果。我想一种方法是使用会刷新的 VBA 代码,但通常的选择、刷新等不起作用。

【问题讨论】:

    标签: r vba excel-formula


    【解决方案1】:

    我能够根据@n8 的建议找到合适的解决方案。这个想法是使用 VBA 代码,该代码将在所有工作簿和所有列上执行文本列。然后使用 VBscript 从 R 调用此 VBA 代码。

    这里是 R 代码:

    library(xlsx)
    wb = loadWorkbook("./source/template.xlsm")
    sh   = wb$getSheet("CAN.FI")
    cell = CellBlock(sheet = sh, startRow = 2, startColumn = 2, noRows = 1, noColumns = 1)
    CB.setMatrixData(cellBlock = cell, x = as.matrix('=SUM(A1:A2)'), startRow = 1, startColumn = 1)
    
    cell = CellBlock(sheet = sh, startRow = 4, startColumn = 4, noRows = 1, noColumns = 1)
    CB.setMatrixData(cellBlock = cell, x = as.matrix('=SUM(A1:A2)'), startRow = 1, startColumn = 1)
    saveWorkbook(wb, file =  "./test.xlsm")
    
    path_to_vbs_file = "./text_to_column.vbs"
    shell(shQuote(normalizePath(path_to_vbs_file)), "cscript", flag = "//nologo")
    

    文件template.xlsm是一个空的.xlsm工作簿,带有一张CAN.FI,该书有一个嵌入的宏/模块,称为“text_to_column()”,宏如下:

    Sub text_to_column()
    Application.ScreenUpdating = False
    On Error Resume Next
    For Each wksht In ActiveWorkbook.Worksheets
     wksht.activate
         For Each col In wksht.Columns
             Columns(col.Column).TextToColumns _
             Destination:=Cells(1, col.Column), _
             DataType:=xlDelimited, _
             TextQualifier:=xlDoubleQuote, _
             ConsecutiveDelimiter:=False, _
             Tab:=True, _
             Semicolon:=False, _
             Comma:=False, _
             Space:=False, _
             Other:=False, _
             FieldInfo:=Array(1, 1), _
             TrailingMinusNumbers:=True
         Next col
    Next wksht
    End Sub
    

    您会在 R 代码的末尾注意到

    path_to_vbs_file = "./text_to_column.vbs"
    

    这指向 vbscript,它只是一个 .vbs 文件。可以从文本文件创建它并更改扩展名。我关注了主题:How To create a vbscript Stackoverflow。我的 .vbs 文件名为:text_to_column.vbs,如下所示:

    Option Explicit
    
    ExcelMacroExample
    
    Sub ExcelMacroExample() 
    
      Dim xlApp 
      Dim xlBook 
    
      Set xlApp = CreateObject("Excel.Application") 
      Set xlBook = xlApp.Workbooks.Open(".\test.xlsm", 0, True) 
      xlApp.Application.Visible = False
      xlApp.DisplayAlerts = False
      xlApp.Run "text_to_column"
      xlApp.ActiveWorkbook.SaveAs ".\test filled.xlsx", 51
    
      xlApp.ActiveWorkbook.Close
      xlApp.Quit
    
      Set xlBook = Nothing 
      Set xlApp = Nothing 
    
    End Sub 
    

    vb 脚本将打开文件 test.xlsm 运行 VBA 宏“text_to_column”,然后将文件以 xlsx 格式保存在名称“testfilled.xlsx”下

    vbscript 从 R 的最后一行开始运行。

    长话短说,代码 R 将打开模板,以字符串格式填充公式,调用将运行宏转换公式的 vbscript。然后将保存具有正确格式的公式的最终文件。

    附带说明,如果你想写公式,你可以考虑使用 ADDRESS 和 INDIRECT 允许你使用行号和列号,这比写 A1 B2 等更容易。一个例子可能是:

    SUM(INDIRECT(ADDRESS(1,1)&":"&ADDRESS(5,1)))
    

    这将做 A1:A5 的总和。

    再次感谢您的帮助,@n8。 希望对大家有所帮助。

    罗曼。

    【讨论】:

    • 仅供参考,Text To Columns 做了很多事情,在您的情况下,您只对格式转换感兴趣。因此,您可以消除整个“分隔符参数”部分:TextQualifier:=xlDoubleQuote, _ ConsecutiveDelimiter:=False, _ Tab:=True, _ Semicolon:=False, _ Comma:=False, _ Space:=False, _ Other:=False, _。它有助于保持代码简洁易读。
    • 会的!感谢您的回答。
    【解决方案2】:

    XLConnectopenxlsx 包似乎更适合处理公式。虽然不确定VBA脚本。

    引用 openxlsx 文档中的示例。

    > library(openxlsx)
    > wb <- createWorkbook()
    > addWorksheet(wb, "Sheet 1")
    > writeData(wb, "Sheet 1", x = iris)
    > v <- c("SUM(A2:A151)", "AVERAGE(B2:B151)") ## skip header row
    > writeFormula(wb, sheet = 1, x = v, startCol = 10, startRow = 2)
    > writeFormula(wb, 1, x = "A2 + B2", startCol = 10, startRow = 10)
    > saveWorkbook(wb, "writeFormulaExample.xlsx", overwrite = TRUE)
    

    对于 XLConnect 也是如此,

    > library(XLConnect)
    > wb <- loadWorkbook("cellFormula.xlsx", create = TRUE)
    > createSheet(wb, "Formula")
    > setCellFormula(wb, "Formula", 1, 1, "SUM($B$1:$B$29)")
    > getCellFormula(wb, "Formula", 1, 1)
              Formula 
    "SUM($B$1:$B$29)" 
    > getCellFormula(wb, 1, 1, 1)
    [1] "SUM($B$1:$B$29)"
    

    或者,可以使用所需的公式和 VB 脚本创建 Excel。并且,选择性地修改excel中的数据。由于其余的公式/脚本没有被修改,Excel 将根据新的输入进行更新。

    例如,假设 Excel“Sheet1”包含 3 列数据,C 列中的公式为 =SUM(A2:B2)。因此,我们可以只修改 A 列和 B 列中的数据,并且由于现有公式,Excel 将针对 C 列进行更新。

    > library(openxlsx)
    > wb <- loadWorkbook("formula-demo.xlsx")
    > # update data in A column
    > writeData(wb, "Sheet1", 21:40, startCol = 1, startRow = 2, colNames = FALSE) 
    Warning message:
    Overwriting existing cell data. 
    > saveWorkbook(wb, "formula-demo.xlsx", overwrite = T)
    

    我希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      我发现使用“文本到列”功能比“格式化”实用程序更彻底地应用格式更改。例如,如果您将一列从一般更改为文本,则所有单元格都不会从“数字”更改为“数字另存为文本”(如左上角的绿色三角形所示),除非您单击单元格并点击进入。而如果您使用“文本到列”实用程序,则整个列都会得到绿色的小三角形。您也可能是这种情况,您可以使用“text-to-columns”实用程序,将您的列指定为“general”。但是,有一个限制,您一次只能做一列。

      另一种解决方案可能是让 Excel 跟踪对工作簿的更改,并将单元格的值重新应用于单元格公式,例如:

      Private Sub Worksheet_Change(ByVal Target As Range)
      
        Target.FormulaR1C1 = Target.Value
      
      End Sub
      

      我怀疑将其放在工作表代码中会导致单元格在更改时重新计算。但是我没有测试过。

      【讨论】:

      • 谢谢!我将测试这两种解决方案,然后再与您联系。
      猜你喜欢
      • 1970-01-01
      • 2016-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多