简体   繁体   English

C ++至VBA(Excel)

[英]C++ to VBA (Excel)

So, basically, in Excel, I have 4 columns of data (all with strings) that I want to process, and want to have the results in another column, like this (nevermind the square brackets, they just represent cells): 因此,基本上,在Excel中,我要处理4列数据(全部带有字符串),并希望将结果放在另一列中,如下所示(不要注意方括号,它们只是表示单元格):

Line    Column1     Column2     Column3     Column4     Result
1:      [a]         [b]         [k]         [YES]       [NO]
2:      [a]         [c]         [l]         [YES]       [NO]
3:      [b]         [e]         []          [YES]       [NO]
4:      [c]         [e]         [f]         [NO]        [NO]
5:      [d]         [h]         [b]         [NO]        [NO]
6:      [d]         []          [w]         [NO]        [NO]
7:      [e]         []          []          [YES]       [NO]
8:      [j]         [m]         []          [YES]       [YES]
9:      [j]         []          []          [YES]       [YES]
10:     []          []          []          [YES]       [YES]

The process that I want the data to go through is this: 我希望数据通过的过程是这样的:

Assume that CheckingLine is the Line for which I currently want to calculate the value of Result, and that CurrentLine is any Line (except CheckingLine) that I am using to calculate the value of Result, at a given moment. 假定CheckingLine是我当前要为其计算Result值的行,并且CurrentLine是我在给定时刻用于计算Result值的任何行(CheckingLine除外)。

  1. If Column4[CheckingLine] is "NO", Result is "NO" (simple enough, no help needed); 如果Column4 [CheckingLine]为“ NO”,则结果为“ NO”(足够简单,不需要帮助);
    1. Example: CheckingLine = 1 -> Column4[1] = "NO" -> Result = "NO"; 示例:CheckingLine = 1-> Column4 [1] =“ NO”->结果=“ NO”;
  2. Else, I want to make sure that all Lines that share a common value with CheckingLine (in any Column between 1 and 3), also have Column4 as "YES" (Doing that would be simple enough even without VBA - in fact, I started by doing it in plain Excel and realised that it wasn't what I wanted) - if that happens, Result is "YES"; 否则,我想确保所有与CheckingLine共享同一值的行(在1到3之间的任何列中)也将Column4设置为“ YES”(即使没有VBA,这样做也很简单-实际上,我已经开始通过在普通的Excel中执行此操作并意识到这不是我想要的)-如果发生这种情况,结果为“是”;
    1. Example: CheckingLine = 8 -> Only shared value is "j" -> CurrentLine = 9 -> Column4[9] = "YES" -> Result = "YES"; 例如:CheckingLine = 8->仅共享值是“ j”-> CurrentLine = 9-> Column4 [9] =“ YES”->结果=“ YES”;
    2. Here's the tricky part: If one of those lines has any value (again, in any Column between 1 and 3) that IS NOT shared with CheckingLine, I want to do the whole process (restart at 1.), but checking the CurrentLine instead. 这是棘手的部分:如果这些行之一具有不与CheckingLine共享的任何值(同样,在1到3之间的任何列中),我想执行整个过程(从1重新开始),而是检查CurrentLine 。
      1. Example: CheckingLine = 2, "a" is shared with Line 1, c is shared with Line 4 -> CurrentLine = 1 -> Column4[1] = "YES", but "b" and "k" are not shared with CheckingLine -> CheckingLine' = 1 -> "b" is shared with Line 5 -> Column4[5] = "NO" -> Result = "NO"; 示例:CheckingLine = 2,“ a”与行1共享,c与行4共享-> CurrentLine = 1-> Column4 [1] =“ YES”,但与CheckingLine不共享“ b”和“ k” -> CheckingLine'= 1->“ b”与第5行共享-> Column4 [5] =“ NO”->结果=“ NO”;

I have written the corresponding C++ code (which works) (and it could have been in any other language, C++ was just the one I was using at the moment) (and the code HAS NOT been optimized in any way, because it's purpose was to be AS CLEAR about its functionality AS POSSIBLE) (the table above is the actual result of running it): 我已经编写了相应的C ++代码(它可以工作)(并且可以用任何其他语言编写,C ++只是我目前使用的那种语言)(并且该代码没有以任何方式进行优化,因为它的目的是尽可能清楚地了解其功能)(上表是运行它的实际结果):

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> column1, column2, column3, column4, contentVector;
unsigned int location, columnsSize;

void InsertInVector(std::string Content)
{
    if(Content == "")
    {
        return;
    }

    for(unsigned int i = 0; i < contentVector.size(); i++)
    {
        if(contentVector[i] == Content)
        {
            return;
        }
    }

    contentVector.push_back(Content);
}

std::string VerifyCurrentVector(unsigned int Start)
{
    std::string result = "";

    if(contentVector.size() == 0)
    {
        result = "YES";
    }
    else
    {
        unsigned int nextStart = contentVector.size();

        for(unsigned int i = 0; i < columnsSize; i++)
        {
            if(i != location)
            {
                for(unsigned int j = Start; j < nextStart; j++)
                {
                    if(column1[i] == contentVector[j])
                    {
                        InsertInVector(column2[i]);
                        InsertInVector(column3[i]);
                    }
                    else if(column2[i] == contentVector[j])
                    {
                        InsertInVector(column1[i]);
                        InsertInVector(column3[i]);
                    }
                    else if(column3[i] == contentVector[j])
                    {
                        InsertInVector(column1[i]);
                        InsertInVector(column2[i]);
                    }
                }
            }
        }

        if(nextStart == contentVector.size())
        {
            for(unsigned int i = 0; i < columnsSize; i++)
            {
                if(i != location)
                {
                    for(unsigned int j = 0; j < nextStart; j++)
                    {
                        if(column1[i] == contentVector[j] || column2[i] ==
                           contentVector[j] || column3[i] == contentVector[j])
                        {
                            if(column4[i] == "NO")
                            {
                                result = "NO";
                                return result;
                            }
                        }
                    }
                }
            }

            result = "YES";
        }
        else
        {
            result = VerifyCurrentVector(nextStart);
        }
    }

    return result;
}

std::string VerifyCell(unsigned int Location)
{
    std::string result = "";
    location = Location - 1;

    if(column4.size() < Location)
    {
        result = "Error";
    }
    else if(column4[location] == "NO")
    {
        result = "NO";
    }
    else
    {
        contentVector.clear();

        InsertInVector(column1[location]);
        InsertInVector(column2[location]);
        InsertInVector(column3[location]);

        result = VerifyCurrentVector(0);
    }

    return result;
}

void SetUpColumns(std::vector<std::string> &Column1, std::vector<std::string> &Column2,
                   std::vector<std::string> &Column3, std::vector<std::string> &Column4)
{
    if(Column4.size() > Column1.size())
    {
        for(unsigned int i = Column1.size(); i < Column4.size(); i++)
        {
            Column1.push_back("");
        }
    }
    if(Column4.size() > Column2.size())
    {
        for(unsigned int i = Column2.size(); i < Column4.size(); i++)
        {
            Column2.push_back("");
        }
    }
    if(Column4.size() > Column3.size())
    {
        for(unsigned int i = Column3.size(); i < Column4.size(); i++)
        {
            Column3.push_back("");
        }
    }

    column1 = Column1;
    column2 = Column2;
    column3 = Column3;
    column4 = Column4;
    columnsSize = Column4.size();
}

int main()
{
    std::vector<std::string> Column1, Column2, Column3, Column4;

    Column1.push_back("a");
    Column1.push_back("a");
    Column1.push_back("b");
    Column1.push_back("c");
    Column1.push_back("d");
    Column1.push_back("d");
    Column1.push_back("e");
    Column1.push_back("j");
    Column1.push_back("j");

    Column2.push_back("b");
    Column2.push_back("c");
    Column2.push_back("e");
    Column2.push_back("e");
    Column2.push_back("h");
    Column2.push_back("");
    Column2.push_back("");
    Column2.push_back("m");

    Column3.push_back("k");
    Column3.push_back("l");
    Column3.push_back("");
    Column3.push_back("f");
    Column3.push_back("b");
    Column3.push_back("w");

    Column4.push_back("YES");
    Column4.push_back("YES");
    Column4.push_back("YES");
    Column4.push_back("NO");
    Column4.push_back("NO");
    Column4.push_back("NO");
    Column4.push_back("YES");
    Column4.push_back("YES");
    Column4.push_back("YES");
    Column4.push_back("YES");

    SetUpColumns(Column1, Column2, Column3, Column4);
    std::cout << "Line\t" << "Column1\t" << "Column2\t" << "Column3\t" << "Column4\t" <<
        std::endl;

    for(unsigned int i = 0; i < Column4.size(); i++)
    {
        std::cout << i + 1 << ":\t" << "[" << column1[i] << "]\t[" << column2[i] <<
            "]\t[" << column3[i] << "]\t[" << column4[i] << "]\t[" << VerifyCell(i + 1)
            << "]" << std::endl;
    }

    return 0;
}

So, after this lengthy explanation, what I want to know is this: 因此,经过冗长的解释,我想知道的是:

  • Is there any way to do this in Excel's VBA (or even better, in plain Excel without VBA)? 在Excel的VBA中有什么方法可以做到这一点(或者在没有VBA的纯Excel中甚至更好)?
  • If not, how can I have my code (which I can easily translate to another C-like language and/or optimise) get the data from, and deliver the results to, Excel? 如果不是,我如何让我的代码(可以轻松地将其转换为另一种类似于C的语言和/或优化)将其从Excel中获取数据并将结果传递给Excel?

Is there any way to do this in Excel's VBA? 在Excel的VBA中有什么方法可以做到这一点?

Yes, you can surely do this with VBA, it is a complete and powerful programming language 是的,您肯定可以使用VBA进行此操作,它是一种完整而强大的编程语言

(or even better, in plain Excel without VBA)? (甚至更好,在没有VBA的纯Excel中)?

Nope. 不。 The calculation seems too complicated to fit with Excel formulae without any VBA code. 该计算似乎过于复杂,无法与没有任何VBA代码的Excel公式配合使用。

If not, how can I have my code (which I can easily translate to another C-like language and/or optimise) get the data from, and deliver the results to, Excel? 如果不是,我如何让我的代码(可以轻松地将其转换为另一种类似于C的语言和/或优化)将其从Excel中获取数据并将结果传递给Excel?

You can access Excel from C++ in many ways. 您可以通过多种方式从C ++访问Excel。 Using ATL is one of them. 使用ATL是其中之一。 another, easier way would be to import/export your Excel file in CSV format, which is easy to parse and write from C++. 另一种更简单的方法是以CSV格式导入/导出Excel文件,该文件易于从C ++解析和编写。 Also consider C#, it has complete COM inter-operability to access office components. 还考虑C#,它具有完全的COM互操作性以访问办公组件。

Ok, if you like to "whipped the code in a rush" then you'll love VBA, next time please try to ask a more specific question. 好的,如果您想“匆忙处理代码”,那么您会爱上VBA的,下次请尝试提出更具体的问题。 Based on code and comments @MikeAscended you're a relatively good programmer, with a grasp of functions/recursion, variable/parameters, conditions, loops, data structures, etc. Re: " I have only touched VBA once in my life and ran away from it" My intent is to get you started and give you syntax here not necessarily a working solution. 根据代码和注释@MikeAscended,您是一个相对不错的程序员,具有函数/递归,变量/参数,条件,循环,数据结构等方面的理解。Re:“我一生只接触过VBA,然后运行远离它”的目的是让您入门并在这里提供语法,不一定是可行的解决方案。 I'm happy to answer any further specific questions you may continue to have. 我很高兴回答您可能还会遇到的其他任何具体问题。

Strategy-wise , I recommend plain VBA which is easy to use in Excel. 从策略角度考虑 ,我建议在Excel中易于使用的纯VBA。 Obviously your problem can be solved in many ways including formulas, however VBA is a powerful tool that any programmer will benefit from using. 显然,您的问题可以通过许多方法解决,包括公式,但是VBA是一个功能强大的工具,任何程序员都可以从中受益。

Code-wise , To start access the editor from Excel press [Alt-F11], or from Design Mode insert and double-click an ActiveX button. 按代码编写,要从Excel开始访问编辑器,请按[Alt-F11],或从“设计模式”插入并双击ActiveX按钮。 To run a macro press [Alt-F8], or in VBA click the green play button. 要运行宏,请按[Alt-F8],或在VBA中单击绿色的播放按钮。

One last note, if you want those line numbers in column 1 in excel then yours will become Column 2-5 or BF. 最后一点,如果您希望在excel的第1列中使用这些行号,则您将成为第2-5列或BF。 I'm assuming you'll use the row numbers in excel so that Column 1 is A, but row 1 will still have titles, so you are staring your data on row 2. 我假设您将使用excel中的行号,以使第1列为A,但第1行仍将具有标题,因此您将数据盯在第2行。

sub processResults_Col5()
' Run This Script as Main()
  dim rowCount as long, i as long 'rowCount  = columnsSize

with sheets(1)
  .Range("A1:D1") = Array("a", "b", "k", "YES")
  ' finish init here
  ' SetUpColumns not necessary in excel

if .cells(2,1).value <> "" then 'do not use .end(xldown) if data is missing
  rowCount = .cells(1,1).end(xldown).row

  for i = 1 to rowCount
    .cells(i,5) = verifyCell(i + 1, rowCount)
  next i

endif 'space will be added :p
end with
end sub

function  verifyCell(rowLocation as long, size as long, optional wSh as excel.worksheet) as string
' the rest should be easy for you to figure out based on C-code
with wSh 
if wsh is nothing then set wsh = activesheet 'let VBA capitalize stuff so you know you typed it correctly
if size < rowlocation then
    verifyCell = "Error" 'the function name is the return value
    'msgbox "Error" ' you can uncomment this line to see error
  elseif cells(rowLocation, 4).value = "NO" then
    cells(rowLocation, 5) = "NO" 'set result
  else
    call InsertInVector(rowLocation) 'CheckingLine
    ' edit the current rowLocation with for loops
    verifyCell = VerifyCurrentVector(0) 'whatever you're doing here
  endif
end with
end function
sub InsertInVector()
end sub
sub VerifyCurrentVector() 'function returns a value
end sub

Some tips: 一些技巧:

  1. Generally, Comment Your Code! 通常,请注释您的代码!
  2. Generally, The first word/acronym of Variable and Object names should start in lowercase, then continue in camel-case. 通常,“变量”和“对象”名称的第一个单词/首字母缩写应以小写字母开头,然后以驼峰大写字母继续。 This helps distinguish them from library types. 这有助于将它们与库类型区分开。
  3. In VBA always put [option explicit] in the beginning of every sheet/module, this requires you to [dim varName as Type] which will help debugging and make your code more explicit so it's easy to understand. 在VBA中,始终在每个工作表/模块的开头都放置[optionexplicit],这要求您将[varName作为Type变暗],这将有助于调试并使代码更明确,以便于理解。
  4. In VBA for numbers use type Long, learn early vs late-binding. 在VBA中,对于数字,请使用Long类型,以了解早期绑定与后期绑定。 If you're instantiating any object that requires a reference/library, always state it explicitly. 如果要实例化任何需要引用/库的对象,请始终明确声明它。 This includes Excel.Worksheet, Excel.Workbook, etc. (eg. you may want your code in MS Access) 这包括Excel.Worksheet,Excel.Workbook等(例如,您可能需要MS Access中的代码)
  5. In Office One of the first settings you're going to want to disable is the popup error window, also use debug.print and the immediate box a few times. 在Office中,您将要禁用的第一个设置是弹出错误窗口,还要使用debug.print和即时框几次。
  6. Generally, as you know from C++ take your time, try to write correct code on your the first try as this will save you debugging time. 通常,正如您从C ++所了解的那样,请花一些时间,尝试在第一次尝试时编写正确的代码,因为这样可以节省调试时间。 Try not to rush and keep coffee & healthy snacks on hand. 尽量不要着急,保持咖啡和健康零食在手。 Good luck and have fun :) 祝好运并玩得开心点 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM