excel函数公式大全 函数

131520人阅读
VLOOKUP函数是Excel中几个最重函数之一,为了方便大家学习,兰色幻想特针对VLOOKUP函数的使用和扩展应用,进行一次全面综合的说明。本文为入门部分
&&&&&一、入门级
&&&&&&VLOOKUP是一个查找函数,给定一个查找的目标,它就能从指定的查找区域中查找返回想要查找到的值。它的基本语法为:
&&&&&&VLOOKUP(查找目标,查找范围,返回值的列数,精确OR模糊查找)
下面以一个实例来介绍一下这四个参数的使用
&&&& 例1:如下图所示,要求根据表二中的姓名,查找姓名所对应的年龄。&&
&&&公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)&&
&& 参数说明:
&&&&&& 1&查找目标:就是你指定的查找的内容或单元格引用。本例中表二A列的姓名就是查找目标。我们要根据表二的“姓名”在表一中A列进行查找。
&&&&&&& 公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)&&&
&&&&&&&2&查找范围(VLOOKUP(A13,$B$2:$D$8,3,0)&):指定了查找目标,如果没有说从哪里查找,EXCEL肯定会很为难。所以下一步我们就要指定从哪个范围中进行查找。VLOOKUP的这第二个参数可以从一个单元格区域中查找,也可以从一个常量数组或内存数组中查找。本例中要从表一中进行查找,那么范围我们要怎么指定呢?这里也是极易出错的地方。大家一定要注意,给定的第二个参数查找范围要符合以下条件才不会出错:
&&&&&&&&A&查找目标一定要在该区域的第一列。本例中查找表二的姓名,那么姓名所对应的表一的姓名列,那么表一的姓名列(列)一定要是查找区域的第一列。象本例中,给定的区域要从第二列开始,即$B$2:$D$8,而不能是$A$2:$D$8。因为查找的“姓名”不在$A$2:$D$8区域的第一列。
&&&&&&& B&该区域中一定要包含要返回值所在的列,本例中要返回的值是年龄。年龄列(表一的D列)一定要包括在这个范围内,即:$B$2:$D$8,如果写成$B$2:$C$8就是错的。
&&&&&& 3&返回&#20540;的列数(B13 =VLOOKUP(A13,$B$2:$D$8,<span style="font-size:24 color:#,0))。这是VLOOKUP第3个参数。它是一个整数&#20540;。它怎么得来的呢。它是“返回&#20540;”在第二个参数给定的区域中的列数。本例中我们要返回的是“年龄”,它是第二个参数查找范围$B$2:$D$8的第3列。这里一定要注意,列数不是在工作表中的列数(不是第4列),而是在查找范围区域的第几列。如果本例中要是查找姓名所对应的性别,第3个参数的&#20540;应该设置为多少呢。答案是2。因为性别在$B$2:$D$8的第2列中。
&&&&&&&4&精确OR模糊查找(VLOOKUP(A13,$B$2:$D$8,3,0)&&),最后一个参数是决定函数精确和模糊查找的关键。精确即完全一样,模糊即包含的意思。第4个参数如果指定&#20540;是0或FALSE就表示精确查找,而&#20540;为1
或TRUE时则表示模糊。这里兰色提醒大家切记切记,在使用VLOOKUP时千万不要把这个参数给漏掉了,如果缺少这个参数默为&#20540;为模糊查找,我们就无法精确查找到结果了。&&
&&&&& 好了,关于VLOOKUP函数的入门级应用就说到这里,VLOOKUP函数可不只是这么简单的查找,我们讲的还只是1/10的用法。其他的没法在一篇文章中说明。敬请期待“VLOOKUP的使用方法-进阶篇”吧。
上一讲咱们学习了VLOOKUP的基本用法和示例,本讲将介绍VLOOKUP在使用中的一些小技巧。
Excel函数速成教程全系列(包括VLOOKUP函数,IF函数,offset函数,sumif函数等66个函数)预计6月初全部录制完成,现已在淘宝开始预订(8折优惠),地址:
一、VLOOKUP多行查找时复制公式的问题
&&& VLOOKUP函数的第三个参数是查找返回&#20540;所在的列数,如果我们需要查找返回多列时,这个列数&#20540;需要一个个的更改,比如返回第2列的,参数设置为2,如果需要返回第3列的,就需要把&#20540;改为3。。。如果有十几列会很麻烦的。那么能不能让第3个参数自动变呢?向后复制时自动变为2,3,4,5。。。&&&
&&&&在EXCEL中有一个函数COLUMN,它可以返回指定单元&#26684;的列数,比如
&&&&&&&& =COLUMNS(A1) 返回&#20540;1
&&&&&&&& =COLUMNS(B1) 返回&#20540;2
&&&而单元&#26684;引用复制时会自动发生变化,即A1随公式向右复制时会变成B1,C1,D1。。这样我们用COLUMN函数就可以转换成数字1,2,3,4。。。&
& & 例:下例中需要同时查找性别,年龄,身高,体重。
&&&& 公式:=VLOOKUP($A13,$B$2:$F$8,COLUMN(B1),0)
& 公式说明:这里就是使用COLUMN(B1)转化成可以自动递增的数字。
二、VLOOKUP查找出现错误&#20540;的问题。
&&&&1、如何避免出现错误&#20540;。
&&&&&EXCEL2003&在VLOOKUP查找不到,就#N/A的错误&#20540;,我们可以利用错误处理函数把错误&#20540;转换成0或空&#20540;。
&&&&& 即:=IF(ISERROR(VLOOKUP(参数略)),&&,VLOOKUP(参数略)
&&&&&EXCEL2007,EXCEL2010中提供了一个新函数IFERROR,处理起来比EXCEL2003简单多了。
&&&& IFERROR(VLOOKUP(),&&)&
&&&&2、VLOOKUP函数查找时出现错误&#20540;的几个原因
&&&&& A、实在是没有所要查找到的&#20540;
&&&&&&B、查找的字符串或被查找的字符中含有空&#26684;或看不见的空字符,验证方法是用=号对比一下,如果结果是FALSE,就表示两个单元&#26684;看上去相同,其实结果不同。
&&&&&&C、参数设置错误。VLOOKUP的最后一个参数没有设置成1或者是没有设置掉。第二个参数数据源区域,查找的&#20540;不是区域的第一列,或者需要反回的字段不在区域里,参数设置在入门讲里已注明,请参阅。
&&&&&D、数&#20540;&#26684;式不同,如果查找&#20540;是文本,被查找的是数字类型,就会查找不到。解决方法是把查找的转换成文本或数&#20540;,转换方法如下:
&&&& 文本转换成数&#20540;:*1或--或/1
&&&&&数&#20540;转抱成文本:&&&&&
&&&& VLOOKUP函数的初级篇就说到这里了,咱们下一讲将介绍VLOOKUP的模糊查找有、反向查找等。
&在学习了VLOOKUP的入门和初级篇后,本文将带将大家学习VLOOKUP的进阶篇:VLOOKUP的模糊查找。
&&&&一、字符的模糊查找&&&&
&&&&&& &在A列我们知道如何查找型号为“AAA”的产品所对应的B列价&#26684;,即:
&&& =VLOOKUP(C1,A:B,2,0)
&&&&&& 如果我们需要查找包含“AAA”的产品名称怎么表示呢?如下图表中所示。
&&& &公式=VLOOKUP(&*&&A10&&*&,A2:B6,2,0) &
&&&&公式说明:VLOOKUP的第一个参数允许使用通配符“*”来表示包含的意思,把*放在字符的两边,即&*& & 字符 & &*&。
&&&二、数字的区间查找
&&&&&&数字的区间查找即给定多个区间,指定一个数就可以查找出它在哪个区间并返回这个区间所对应的&#20540;。
&&&&在VLOOKUP入门中我们提示VLOOKUP的第4个参数,如果为0或FALSE是精确查找,如果是1或TRUE或省略则为模糊查找,那么实现区间查找正是第4个参数的模糊查找应用。
&&&&首先我们需要了解一下VLOOKUP函数模糊查找的两个重要规则:
&&& 1、引用的数字区域一定要从小到大排序。杂乱的数字是无法准确查找到的。如下面A列符合模糊查找的前题,B列则不符合。&
&&& 2、模糊查找的原理是:给一定个数,它会找到和它最接近,但比它小的那个数。详见下图说明。
&&&最后看一个实例:&
&&&&例:如下图所示,要求根据上面的提成比率表,在提成表计算表中计算每个销售额的提成比率和提成额。
&& 公式:=VLOOKUP(A11,$A$3:$B$7,2)
&&&公式说明:
&&& 1、上述公式省略了VLOOKUP最后一个参数,相当于把第四个参数设置成1或TRUE。这表示VLOOKUP要进行数字的区间查找。
&&& 2、图中公式中在查找5000时返回比率表0所对应的比率1%,原因是0和1最接近,但VLOOKUP只选比查找&#20540;小的那一个,所以公式会返回0所对应的比率1%。
&前言:前面我们分别学习了VLOOKUP函数的入门、初级和进阶篇。今天我们学习VLOOKUP函数的高级应用部分-VLOOKUP函数的数组应用。(本文由兰色幻想原创,转载请注明转自)
&一、VLOOKUP的反向查找。
&&& 一般情况下,VLOOKUP函数只能从左向右查找。但如果需要从右向右查找,则需要把区域进行“乾坤大挪移”,把列的位置用数组互换一下。
&&&&例1:要求在如下图所示表中的姓名反查工号。
&&&&公式:=VLOOKUP(A9,IF({1,0},B2:B5,A2:A5),2,0)
&&&&公式剖析:
&&&&&&& 1、这里其实不是VLOOKUP可以实现从右至右的查找,而是利用IF函数的数组效应把两列换位重新组合后,再按正常的从左至右查找。
&&&&&&& 2、IF({1,0},B2:B5,A2:A5)这是本公式中最重要的组成部分。在EXCEL函数中使用数组时(前提时该函数的参数支持数组),返回的结果也会是一个数组。这里1和0不是实际意义上的数字,而是1相关于TRUE,0相当于FALSE,当为1时,它会返回IF的第二个参数(B列),为0时返回第二个参数(A列)。根据数组运算返回数组,所以使用IF后的结果返回一个数组(非单元&#26684;区域):{&张一&,&A001&;&赵三&,&A002&;&杨五&,&A003&;&孙二&,&A004&}
&二、VLOOKUP函数的多条件查找。
&&&&& VLOOKUP函数需要借用数组才能实现多条件查找。
&&&&&例2:要求根据部门和姓名查找C列的加班时间。
&&&& 分析:我们可以延用例1的思路,我们的努力方向不是让VLOOKUP本身实现多条件查找,而是想办法重构一个数组。多个条件我们可以用&连接在一起,同样两列我们也可以连接成一列数据,然后用IF函数进行组合。
&&&&公式:{=VLOOKUP(A9&B9,IF({1,0},A2:A5&B2:B5,C2:C5),2,0)}
&&&&公式剖析:
&&&&&& 1、A9&B9 把两个条件连接在一起。把他们做为一个整体进行查找。
&&&&&& 2、A2:A5&B2:B5,和条件连接相对应,把部分和姓名列也连接在一起,作为一个待查找的整体。
&&&&&& 3、IF({1,0},A2:A5&B2:B5,C2:C5) 用IF({1,0}把连接后的两列与C列数据合并成一个两列的内存数组。按F9后可以查看的结果为:
&&&&&& {&销售张一&,1;&销售赵三&,5;&人事杨五&,3;&销售赵三&,6}
&&&&&& 4、完成了数组的重构后,接下来就是VLOOKUP的基本查找功能了,另外公式中含有多个数据与多个数据运算(A2:A5&B2:B5),,所以必须以数组形式输入,即按ctrl&#43;shift后按ENTER结束输入。
&&&& 三、VLOOKUP函数的批量查找。
&&&&&VLOOKUP一般情况下只能查找一个,那么多项该怎么查找呢?
&&&&&例3 要求把如图表中所有张一的消费金额全列出来
&&&&&分析:经过前面的学习,我们也有这样一个思路,我们在实现复杂的查找时,努力的方向是怎么重构一个查找内容和查找的区域。要想实现多项查找,我们可以对查找的内容进行编号,第一个出现的是后面连接1,第二个出现的连接2。。。
&&&& 公式:{=VLOOKUP(B$9&ROW(A1),IF({1,0},$B$2:$B$6&COUNTIF(INDIRECT(&b2:b&&ROW($2:$6)),B$9),$C$2:$C$6),2,)}
&&&& 公式剖析:
&&&&&&& 1、B$9&ROW(A1) 连接序号,公式向下复制时会变成B$9连接1,2,3
&&&&&&&&2、给所有的张一进行编号。要想生成编号,就需要生成一个不断扩充的区域(INDIRECT(&b2:b&&ROW($2:$6)),然后在这个逐行扩充的区域内统计“张一”的个数,在连接上$B$2:$B$6后就可以对所有的张一进行编号了。
&&&&&&&3、IF({1,0}把编号后的B列和C组重构成一个两列数组
&&&& 通过以上的讲解,我们需要知道,VLOOKUP函数的基本用法是固定的,要实现高级查找,就需要借助其他函数来重构查找内容和查找数组。
&&&& 至此VLOOKUP函数从入门到高级的四篇VLOOKUP函数使用教程全部结束了,VLOOKUP函数在数组运算中还有着其他应用,但只是配角了,所以本系列不再介绍。由于笔者水平有限,不免有错漏之处,请大家多多指点。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:336938次
积分:2896
积分:2896
排名:第6097名
原创:21篇
转载:263篇
评论:28条
(2)(7)(10)(12)(9)(5)(4)(5)(4)(5)(10)(16)(12)(3)(13)(2)(3)(9)(8)(13)(3)(15)(5)(7)(6)(1)(2)(5)(3)(29)(37)(12)(1)(4)(1)(2)&&& 我们知道,Excel中有很多内置的函数,比如求和,求平均,字符串操作函数,金融函数等等。在有些时候,结合业务要求,这些函数可能不能满足我们的需求,比如我想要一个函数能够从WebService上获取某只股票的最新价;我想要一个函数能够获取当前的天气情况,这些需求我们可以通过编写Excel自定义函数(User Define Function ,UDF )来实现,这样,在Excel中直接调用我们的自定义函数即可满足特定的业务需求,一般地,因为这种自定义函数的粒度相对较小,所以我们可以根据业务需求编写很多基础的自定义函数,然后以这些自定义函数为基础,编写各种复杂的分析报表。
&&& 编写UDF的方式有很多种,比如直接在VBA种编写自定义函数;如果您熟悉C++,可以将自定义函数编写到XLL中,不熟悉也可以使用ExcelDNA这个开源的库使用.NET技术也可以将您的代码编译为XLL;如果熟悉.NET,使用C#编写自定义函数类库,然后将类库注册成Com组件也可在Excel中调用。下面就这几种方式简要介绍,并给出其优缺点。
1. 使用C# 类库注册的方式实现Excel自定义函数
&&& 我自己对.NET 较熟悉,所以首先介绍这种在.NET中即可进行Excel自定义函数开发的模式,这种方法相对简单。在开始之前,还是回到我们对YY插件的规划,我们的YY插件有天气,财经,地图等功能,现在我们假设需要一个天气自定义函数,通过该函数能够获取某个城市某一天的天气情况,比如说气温。
&&& 首先我们需要创建一个简单的C#类库,如下图,其名为YYWeatherUDF。
&&& 然后,我们创建一个所有自定义函数的基类UDFBase.cs,在该类中,我们放一些基本的注册Com组件所需要的一些操作以及屏蔽一些Object的对象的方法使其不要出现在Excel的UDF函数中来。有一点需要注意的是,在注册及取消注册为Com组件的时候,为避免Excel找不到mscoree.dll,需要往注册表中写入其全部路径,下面的代码即为实现这一功能。
public abstract class UDFBase
/// &summary&
/// 解决在某些机器的Excel提示找不到mscoree.dll的问题
/// 这里在注册表中将该dll的路径注册进去,当使用regasm注册该类库为com组件
/// 时会调用该方法
/// &/summary&
/// &param name="type"&&/param&
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
Registry.ClassesRoot.CreateSubKey(
GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(
GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll",
RegistryValueKind.String);
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
Registry.ClassesRoot.DeleteSubKey(
GetSubKeyName(type, "Programmable"), false);
private static string GetSubKeyName(Type type, string subKeyName)
return string.Format("CLSID\\{{{0}}}\\{1}", type.GUID.ToString().ToUpper(), subKeyName);
&&& 将工程的AssemblyInfo.cs 中的[assembly: ComVisible(true)]。还有一点需要注意的是,Object类还有四个公共方法,如果直接继承的话,这四个方法还是会出现在我们的UDF函数中,要避免Object对象的其中三个公共方法出现在UDF列表中,可以重写对三个方法设置ComVisible自定义属性。但是第四个GetType方法不允许重写,所以还是会出现在UDF中。要解决这一问题,我们不能使用类了,要使用接口,然后将接口暴露为Interface,具体做法可以参见 和
这里为了简洁和取舍,暂采用抽象类的方式处理。
/// &summary&
将Object类的四个公共方法隐藏
否则将会出现在Excel的UDF函数中
/// &/summary&
/// &returns&&/returns&
[ComVisible(false)]
public override string ToString()
return base.ToString();
[ComVisible(false)]
public override bool Equals(object obj)
return base.Equals(obj);
[ComVisible(false)]
public override int GetHashCode()
return base.GetHashCode();
&&& 以上这些代码是一个在C# 创建一个UDF类的基本代码,我们可以将该代码保存为基类。
&&& 现在我们要编写我们自己的实际的UDF函数了,新建一个名为WeatherFunc的类,继承自上面的UDFBase抽象类,并在类的属性上添加一些自定义属性,这些属性在后面注册为Com组件的时候需要用到。ClassInterface类的构造函数中参数ClassInterfaceType.AutoDual表示两边都传递,这就回是的Object类的所有公共方法都会显示出来,如果采用实现接口的方式,将该熟悉设置为None即可解决多余方法出现在UDF列表中的问题,这里不细讲,继续。
[Guid("5268ABE2-9B09-439d-BE97-2EA60E103EF6")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class WeatherFunc : UDFBase
public WeatherFunc()
&&& 其中Guid可以使用Visual Studio自带的工具生成,如果我们不指定,则Visual Studio在将该类注册为Com组件时,调用regasm工具的时候会自动生成一个Guid,在开发过程中,一般我们会手动指定一个Guid,这样在调试的时候我们可以根据Guid在注册表中去查找该项,看是否正常注册为了Com组件。
&&& 然后我们在WeatherFunc中定义三个public方法,分别为YY_Weather_Condition ,YY_Weather_Temperture和YY_Weather_WindSpeed 这三个函数分别用来获取天气描述,气温和风速。 这里的天气情况使用了Yahoo Weather API,您可以参考,API请求的格式中w代表城市编号,u代表单位,以上海为例,其请求的url为,他的返回格式是一个xml文件。这里我创建了一个Weather类对该接口进行了封装,由于这里重点讲解UDF,故不做展开。
/// &summary&
/// 根据城市和日期,返回当天的天气描述
/// &/summary&
/// &param name="city"&城市&/param&
/// &param name="day"&日期&/param&
/// &returns&&/returns&
public String YY_Weather_Condition(String city, DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Condition.T
/// &summary&
/// 根据城市和日期,返回当天的气温状况
/// &/summary&
/// &param name="city"&城市&/param&
/// &param name="day"&日期&/param&
/// &returns&&/returns&
public double YY_Weather_Temperature(String city, DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Condition.T
/// &summary&
/// 根据城市和日期,返回当天的风速
/// &/summary&
/// &param name="city"&城市&/param&
/// &param name="day"&城市&/param&
/// &returns&&/returns&
public double YY_Weather_WindSpeed(String city, DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Wind.S
&&& 这样我们的三个UDF函数已经写好了,然后右击工程项目,在属性设置-〉生成 注册为Com组件。
&&& 这里注册为Com组件时,Visual Studio其实是去调用regasm 将类库注册为Com组件,并在注册表里面写入一些信息。在发布到客户端上部署的时候,我们可以直接导入该类库的相关注册表信息,或者直接调用regasm在客户的机器上写入这些信息,在后面讲到Excel插件安装部署的时候,会说到这些。
&&& 然后我们直接进行编译。因为注册Com组件涉及对注册表进行操作,在XP以上系统中,需要管理员权限,如果当前Visual Studio不是以管理员身份运行。则会出现下面错误:
保存退出,然后右键选择以管理员权限打开VS,然后重新编译。
&&& 完成之后,我们根据之前的GUID 5268ABE2-9B09-439d-BE97-2EA60E103EF6 到注册表中去查找,可以看到,编译并注册为Com组件后会到注册表中写入一些信息,这些情况在安装Office等软件的时候,最后一步的时候,一般可以看到正在注册组件,然后后面是不停闪动GUID,应该是在做相同的工作。我机器上截图如下。
现在我们打开Excel软件,在开发工具-〉加载项中,将我们的自定义函数加载进来。
现在,在公式-&插入函数中可以看到我们编写的自定义函数。
&&& 可以看到我们之前编写的两个UDF函数,那个GetType是因为我们继承自抽象类的缘故,其中三个已经被重写对Com不可见,GetType方法不能被重写,没有被移除,前面介绍了采用暴露接口的方式可以解决这一问题,需要将我们所有的UDF函数以接口的形式定义,然后在类中实现。这里就不多讲了。
&&& 点击相应的函数,即可弹出参数选择框:
&&& 自此,采用.NET编写自定义函数介绍完了,他的好处是编写方便,如果您熟悉.NET的话,相当于就是编写了一个特殊的类库。当然也有一些缺点,比如说,在Excel中输入函数的时候,没有AutoComplete支持,并且在界面上不能显示参数的解释和函数的解释,Com的注册和注销都需要对注册表进行读写操作,在安装部署的时候可能需要一些注册表读写权限以及需要某些杀毒软件的放行,一般地,因为我们的插件再安装的时候是一定需要道注册表中注册的,所以一般的UDF函数的注册对注册表的读写时是和插件安装一同进行的;UDF函数使用.NET 编写容易反编译;仅支持Excel 2003及以上版本。不过由于这种方式简单,所以仍然是很多开发UDF函数的可选方案。
2. VBA 的方式编写自定义函数
&&& 相信使用Excel比较多的人对VBA比较熟悉,VBA其实就是Excel里面的脚本,通过VBA也可以编写自定义函数,存放到某个Sheet页或者作为一个独立的Excel脚本文件比如xla
文件存放。一般的,我们会将我们的自定义函数存在单独的Excel脚本.xla文件中,然后在系统加载的时候,将该脚本文件加载进来。然后就可以直接使用里面编写的UDF函数了。
&&& 这里我们打开一个Excel文件,然后按Alt+F11打开VBA编辑器。
然后可以看到VBA 的IDE界面了,这时候,我们对着工程文件点击,新添加一个模块:
&&& 在该模块中写两个简单的函数。这一回,我们要编写查找天气最高温度,最低温度的两个函数。命名为YY_Weather_TemperatureHigh,YY_Weather_ TemperatureLow。这里先简单写个假数字。
&&& 完成后,保存为.xla文件。然后回到Excel界面,现在我们在单元格中输入我们的自定义函数的时候,当我们输入YY的时候,就有AutoComplete提示了,Excel 2003以上版本会为我们列出所有匹配以YY开头的内置函数和自定义函数了。
&&& Excel函数只能提示界面上,按上,下键可以选择,按Tab键确认。输入YY_Weather_TemperatureHigh的时候,单元格会返回30,输入YY_Weather_TemperatureLow,单元格返回20,这两个数字是我们硬编码进去的。这就是在VBA中编写UDF函数的方式,简单吧。如果逻辑比较简单的话,您完全可以使用VBA语言来实现您的逻辑,比如说在VBA里面去查询数据库,去访问WebService等等。
&&& 如果您对VBA不熟悉的话,也没关系,VBA中也可以调用C# 类库中编写的方法。我们可以使用VBA来编写UDF函数的签名,然后在VBA方法体内调用C# 里面的方法。现在我们将前面的两个取最高,最低气温的函数换成我们之前写好的通过Weather类获取气温的代码。
&&& 要在VBA中调用C#中的方法,首先我们需要在文章中的SharedAddin程序的基础上进行,我们添加FunctionHelper类,并让其继承自StandardOleMarshalObject对象,然后提供一些对Weather函数进行包装的方法。代码如下:
public class FunctionHelper:StandardOleMarshalObject
public object GetWeather_TemperatureHigh(string city,DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Forecast.Days[0].H
public object GetWeather_TemperatureLow(string city, DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Forecast.Days[0].L
&&& 然后,在Connect类的OnConnection中将ComAddin实例对象的Object的属性设置为FunctionHelper实例对象:
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
applicationObject = application as Application;
addInInstance = addInInst as COMAddIn;
addInInstance.Object = new FunctionHelper();
if (applicationObject.Version == "11.0")
if (menuDesigner == null)
menuDesigner = new MenuDesigner(applicationObject);
menuDesigner.AddMenus();
menuDesigner.AddToolBars();
&&& 然后在VBA中,我们根据ProgId查找我们的插件。
Public Function GetCOMAddIn(Optional addInName As String) As COMAddIn
Dim YYAddIn As COMAddIn
If addInName = "" Then
addInName = "YYSharedAddin"
Dim addInItem As COMAddIn
For Each addInItem AddIns
If addInItem.Description = addInName Then
Set YYAddIn = addInItem
Next addInItem
Set GetCOMAddIn = YYAddIn
End Function
&&& 这里我们之前的插件叫YYSharedAddin,然后改写我们的之前写过的两个函数:
'获取名为city的城市的当天的最高气温
Function YY_Weather_TemperatureHigh(city As String, day As Date)
Dim YYAddIn As COMAddIn
Dim dataQuery As Object
Set YYAddIn = GetCOMAddIn("YYSharedAddin")
Set dataQuery = YYAddIn.Object
YY_Weather_TemperatureHigh = dataQuery.GetWeather_TemperatureHigh(city, day)
End Function
'获取名为city的城市的当天的最低气温
Function YY_Weather_TemperatureLow(city As String, day As Date)
Dim YYAddIn As COMAddIn
Dim dataQuery As Object
Set YYAddIn = GetCOMAddIn("YYSharedAddin")
Set dataQuery = YYAddIn.Object
YY_Weather_TemperatureLow = dataQuery.GetWeather_TemperatureLow(city, day)
End Function
&&& 可以看到YYAddin.Object对象在我们的Connect类的OnConnect的时候已经赋值为了FunctionUtility的实例类,所以后面我们在VBA里可以直接调用里面的C# 方法了。
&&& 将上面的VBA保存为Excel .xla格式的宏文件。然后在VBA中和Visual Studio中C#函数方法体内设置断点,在Sheet页中输入我们的自定义函数,然后可以看到VBA中的断点被命中,注意在VBA IDE中,逐步运行调试的快捷键是F8,当调试我们的dataQuery.GetWeather_TemperatureHigh这一句时,会跳到Visual Studio中的C#函数内部,在VS中逐步调试的快捷键是F11,有意思吧。
&&& 一般地,我们会将自定义UDF的签名放到Excel 宏文件中以.xla文件保存,然后在方法体内调用C#方法。以YY插件项目为例,当程序运行的时候,在Connect类的OnConnect方法中我们可以使用以下方法加载.xla宏脚本文件到Excel中。
string basePath = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullN
LoadUDFs(basePath + "\\YYFunc.xla", true);
public bool LoadUDFs(string progID, bool load)
bool loaded = false;
if (File.Exists(progID))
AddIn udfAddIn = applicationObject.AddIns.Add(progID, true);
udfAddIn.Installed =
loaded = udfAddIn.I
catch { loaded = false; }
&&& 其中progID传入我们脚本文件名加路径,load为true。
&&& 一般地,采用VBA的方式来编写UDF函数简单快捷,而且比较灵活方便调试,对于一些复杂的逻辑,可以将方法体的实现逻辑放置到C#代码中,在Excel 03以上版本,还有Excel智能提示的支持,在注册的时候,不需要对注册表进行读写操作。但是这种方式也有一些缺点:
VBA脚本安全性比较差,虽然可以对我们的脚本设置密码,但这种密码相当容易被破解,破解的手段并不需要太复杂的枚举或者遍历逻辑,在前一篇文章中我们可以看到,破解的过程只需要将原先的脚本文件的保护密码设置为另外一个密码覆盖之前的密码即可,然后再次打开用这个密码打开,然后取消密码保护即可。
VBA脚本是一种解释型的脚本语言,运行的时候是逐条语句边解释边执行的,这些和采用之前的Com组件方式的编译为二进制和后面直接编译为xll的方式相比,运行效率较低。
3. XLL方式编写自定义函数
&&& XLL是Excel自97版本就支持的一种外接二进制插件,其运行速度较前面的两种方式快,并且有更多强大的功能,但是XLL通常使用C或者C++编写,对于开发者的要求较高。关于XLL开发在的参考资料中有一本 讲的比较深入,有兴趣的同学可以看看。
&&& 幸运的是,有一个名为的开源库使得我们使用.NET语言即可编写XLL程序。使用ExcelDNA很简单,官网上的也很详细,这里简要介绍一下如何使用ExcelDNA来编写XLL自定义函数。当然一开始我们需要到官网上下载安装包:
&&& 先建一个C# 类库,然后引用下载文档中的ExcelDna.Integration.dll,创建两个公共的静态的方法,这里为了完善我们的歪歪天气函数,我们创建两个函数YY_Weather_Condition,YY_Weather_Sunrise分别用来获取对天气的描述信息和当天的日出时间。
public class YYWeather
[ExcelFunction(Description = "获取指定城市的最新的天气信息")]
public static string YY_Weather_Condition(string city, DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Condition.T
[ExcelFunction(Description = "获取指定城市的日出时间")]
public static DateTime YY_Weather_Sunrise(string city, DateTime day)
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
return weather.Astronomy.S
&&& 然后在项目中添加一个名为YYWeather.dna的文本文件。
&DnaLibrary Name="YY Weather Fucntion" RuntimeVersion="v4.0"&
&ExternalLibrary Path="YYWeatherUDFExcelDNA.dll" /&
&/DnaLibrary&
&&& 然后将安装包内的ExcelDna.xll文件拷贝到项目内,并将其命名为YYWeather.xll,然后将其包含在项目中,设置其生成属性,保证其在编译时会拷贝到生成目录下。
&&& 点击生成的YYWeather.xll文件,然后先建一个Sheet页,在打开的Excel Sheet页中输入YY,可以看到,我们之前建立的两个自定义函数给予了提示。
&&& 选择天气状况函数,输入城市和日期,可以看到返回了正确的天气状况信息,多云天气
&&& 另外在插入函数的时候,可以看到,对函数和参数有提示:
&&& 我们选择查询日出函数,输入城市和时间之后,可以看到能够返回正确的结果。
&&& 另外,在使用ExcelDNA时,比如上面的例子中,我们可以看到一堆的xll, dna, dll文件,不方便发布和部署。ExcelNDA提供了一个打包工具,可以将这些文件打包成一个xll文件,使用下载包内的默认打包程序ExcelDnaPack.exe即可实现这一功能,将ExcelDNAPack.exe拷贝到生成目录,并在cmd下将当前目录切换到生成目录下,命令行下运行程序,并将YYWeather.dna作为参数传递进行:
&&& 程序会生成YYWeather-packed.xll,这个即为生成好的xll文件,他会将dll中的内容打包到xll中去,分发部署的时候,只需要将这个文件发布到用户的机器上即可。
&&& 一般地,在实际的开发环境中,以歪歪插件为例,和加载xla宏脚本文件一样,在Connect的Onconnect方法中调用之前的LoadUDFs传入该xll的完整路径和文件名即可使用里面的自定义函数了。
string basePath = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullN
LoadUDFs(basePath + "\\YYWeather-packed.xll", true);
&&& ExcelDNA功能强大,这里只是简要介绍了如何使用.NET语言编写UDF函数,ExcelDNA支持VBA语言,F#语言,还可以实现Ribbon菜单,RTD函数,异步UDF函数等,这些后面会介绍。
&&& 借助ExcelDNA编写xll的UDF有很多优点,比如说,运行速度快;Excel 2003以上版本支持函数的AutoComplete;支持函数和函数参数的注释;不用对注册表进行读写;使用.NET 借助ExcelDNA开发门槛相对较低等优点,在大多数情况下是比较理想的解决方案。
&&& 另外,ExcelDNA的函数提示,仅支持1000个UDF,就是说超过1000个,当您在Excel中输入的时候,下拉提示框中,超出的部分函数可能不会出现。这可能是ExcelDNA的开发者考虑到过多的提示项对增加内存消耗的原因。解决方法很简单,您只需要下载ExcelDNA的源代码,搜索1000,然后改为您想要的数字,然后在有些地方添加一些代码。编译一下即可。
&&& 最后,使用上面的方式创建好了UDF之后,我们来创建一个简单的天气预报报表,我录制了一个小动画,如下图,您应该可以体会到Excel自定义函数的强大用处:
&&& Excel 中的自定义函数极大地扩充了Excel的应用领域,他也是Excel插件和业务逻辑的一个极好的接入点,通过Excel UDF函数,您可以在此基础上创建各种灵活的分析报表,构建各种分析模型。本文简要介绍了常见的三种编写Excel UDF函数的方法,他们是采用.NET 托管代码注册为Com组件的方式,纯VBA脚本和VBA调用.NET 类库方式,以及借助Excel结合.NET 编写xll的方式,三种方式各有优缺点,现简单总结如下:
.NET Automation Add-Ins
1. 简单,有.NET基础即可。
2. 不需要借助任何第三方类库即可实现。
3. 运行速度较快
4. 安全性较高
1. Excel 2003版本不支持AutoComplete
2. 在插入函数界面上,不支持函数及参数注释
3. 需要对注册表进行读写操作。
1. 简单灵活易调试,有VBA基础即可编写,其实现既可以全部使用VBA,也可以在VBA中调用其它第三方类库。
2. 拥有Excel 函数的智能提示的支持。
1. 安全性较差,非常容易被破解。
2. 插入函数界面上,不支持函数体及参数注释
3. 运行效率低下,和编译型语言相比,VBA本质上是解释型语言,边解释边执行,效率慢。
1. 运行速度快,由于事先编译为了二进制代码,直接加在到内存中执行,较VBA方式快。
2. 安全性较高,一般采用C或者C++ 编写,代码发布后为二进制,反编译难度大。
3. 拥有Excel函数智能提示支持。
4. 插入函数界面支持函数体和函数参数注释。
1.采用纯C或者C++开发难度较大。采用ExcelDNA支持.NET 编写XLL大大降低开发难度。但是这是在第三方工具的支持下进行的。
&&& 下文将会介绍Excel中的另外一类比较重要的函数,Real Time Data 即RTD函数,这一类型的函数可以实现诸多强大的功能,比如在Excel中实现股票行情信息的实时刷新,实现Excel 异步自定义函数功能等等,敬请期待。
&&& 本文所有代码点击下载,希望本文对您了解Excel自定义函数有所帮助。
阅读(...) 评论()

我要回帖

更多关于 excel函数应用实例 的文章

 

随机推荐