C#中怎么实现c 调用excel函数数

对于Excel的数据处理功能,大家都已经了解。
我们经常需要将数据导入到Excel,或直接打开Excel文档,读写文件操作,这需要用到ExcelHelper类,有了这个类,这些操作大大的减少我们工作量。
ExcelHepler.cs这个类,我博客上有完整的代码。
至于如何用,这里不一一说明,相信大家琢磨一下就可以写出。
言归正传,我们要讨论的事,Excel的函数如何给.NET使用。众所周知,Excel的函数强大,及其使用方法都被我们所接受。有时为了一个不常用NET的函数,要费九牛二虎之力,自己写函数或找开源代码,最后也不是很理想,若我们直接调用Excel现成的函数,那该有多好啊。
一、找到相就的Excel包含函数库文件
三个Excel的库文件,下载地址&
这里包含了三个件Interop.Excel.dll Interop.Office.dll Interop.VBIDE.dll,其中与本文直接相关的Interop.Excel.dll,为了减少程序出错,及保证完整性,建议童鞋们一起用,否则出错了都不知那个原因。
二、将库导入相应的项目中
在解决方案中右键点引用,选择&添加引用&将三个下载的库文件添加,如图
using&&&E&&&
下面以IsNumber函数作为例子。先声明一个实例,这样直接调用相应函数
Microsoft.Office.Interop.Excel.ApplicationClass&&&excel=&&&
new&&&Microsoft.Office.Interop.Excel.ApplicationClass();&&&
bool&&&b=excel.WorksheetFunction.IsNumber(&"ABC&");&&&
可用的函数非常多,函数的参数也提示给你了,若还不知道该函数的使用方法,可以到Excel中找相应的函数说明。如图
本文介绍 Microsoft Excel 中&PV&的公式语法和用法。
返回投资的现值。现值为一系列未来付款的当前值的累积和。例如,借入方的借入款即为贷出方贷款的现值。
PV(rate, nper, pmt, [fv], [type])
PV 函数语法具有下列:
&&&&必需。各期利率。例如,如果按 10% 的年利率借入一笔贷款来购买汽车,并按月偿还贷款,则月利率为 10%/12(即 0.83%)。可以在公式中输入 10%/12、0.83% 或 0.0083 作为 rate 的值。
&&&&必需。年金的付款总期数。例如,对于一笔 4 年期按月偿还的汽车贷款,共有 4*12(即 48)个偿款期。可以在公式中输入 48 作为 nper 的值。
&&&&必需。各期所应支付的金额,其数值在整个年金期间保持不变。通常,pmt 包括本金和利息,但不包括其他费用或税款。例如,¥10,000 的年利率为 12% 的四年期汽车贷款的月偿还额为 ¥263.33。可以在公式中输入 -263.33 作为 pmt 的值。如果省略 pmt,则必须包含 fv 参数。
&&&&可选。未来值,或在最后一次支付后希望得到的现金余额,如果省略 fv,则假设其值为 0(例如,一笔贷款的未来值即为 0)。例如,如果需要存 ¥50,000 以便在 18 年后为特殊项目付款,则 ¥50,000 就是未来值。可以根据保守估计的利率来决定每月的存款额。如果省略 fv,则必须包含 pmt 参数。
&&&&可选。数字 0 或 1,用以指定各期的付款时间是在期初还是期末。
TYPE&值支付时间
应确认所指定的 rate 和 nper 单位的一致性。例如,同样是四年期年利率为 12% 的贷款,如果按月支付,rate 应为 12%/12,nper 应为 4*12;如果按年支付,rate 应为 12%,nper 为 4。
以下函数应用于年金:
CUMIPMTPPMT
FVSCHEDULE
年金是在一段连续期间内的一系列固定的现金付款。例如汽车贷款或购房贷款就是年金。有关详细信息,请参阅各年金函数的详细说明。
在年金函数中,支出的款项,如银行存款,表示为负数;收入的款项,如股息收入,表示为正数。例如,对于储户来说,¥1000 银行存款可表示为参数 -1,000,而对于银行来说该参数为 1000。
下面列出的是 Microsoft Excel 进行财务运算的公式,如果 rate 不为 0,则:
如果 rate 为 0,则:
(pmt * nper) + pv + fv = 0
如果将示例复制到一个空白工作表中,可能会更容易理解该示例。
每月底一项保险年金的支出
投资收益率
付款的年限
说明(结果)
=PV(A3/12, 12*A4, A2, , 0)
在上述条件下年金的现值 (-59,777.15)。
结果为负值,因为这是一笔付款,亦即支出现金流。如果年金的购买成本是 (60,000),则您可以确定这不是一项合算的投资,因为年金的现值 (59,777.15) 小于实际支付值。
&注释&&&利率除以 12 得到月利率。支付的年数乘以 12 得到支付次数。
此文章对您是否有帮助?
阅读(...) 评论()&&& 介绍了Excel中的自定义函数(UDF ),它极大地扩展了Excel插件的功能,使得我们可以将业务逻辑以Excel函数的形式表示,并可以根据这些细粒度的自定义函数,构建各种复杂的分析报表。
&&& 普通的UDF自定义函数的基本执行逻辑是,Excel接受用户输入的函数表达式,然后通过UDF函数的处理逻辑进行处理,在处理过程中,Excel 的UI界面会一直等待函数体执行完成之后更新单元格数据。和大多数同步应用一样,同步的UDF函数会阻塞Excel UI线程,并且不方便动态扩展计算能力,在处理逻辑比较复杂、进行耗时的计算逻辑的时候,会造成较差的用户体验。所以我们需要开发异步的UDF函数。
一 问题的提出
&&& 通常,当用户在Excel中输入自定义函数的时候,我们希望实现以下表现:
开启另外一根线程或者在线程池中处理函数计算逻辑(不同于Excel UI线程)。
同时立即返回&Calculating&,&Fetching&或&Loading&等值提示用户正在计算。
待计算完成之后,通知Excel重新计算该单元格。
返回真正的计算结果。
&&& 以上步骤中,难点在于第三步,一般的函数在第二步返回值之后,整个过程就结束了。由于函数计算不在Excel主线程中,而刷新Excel单元格重新计算时要在Excel 主线程中进行,并且要刷新哪一个单元格还需要指明,而且在异常处理上比较麻烦。
&&& 在Excel 2010中,提供了直接的能力,不过只有在使用C/C++开发的XLL Addin中才能使用,并且不向下兼容。要编写适用于大多数版本的Excel(03及以上版本)必须使用Excel已经提供的编程机制。我们可以利用在函数来解决以上问题,Excel RTD机制是Excel 2002就引入的,因此向上兼容性良好。使用Excel RTD来实现异步UDF函数的基本原理是,当用户在单元格输入函数时:
将函数以RTD函数请求,记录下TopicID,以及请求的表达式及参数,并返回&Calculating&提示用户正在处理
开辟另外线程处理该TopicID对应的Excel请求,并计算出结果,保存。
调用UpdateNotify方式,请求Excel重新计算单元,在重新计算的单元格中,根据TopicID,以及计算的结果值,返回给Excel
Excel根据返回的计算结果值,刷新单元格。
根据以上分析,为Excel编写异步UDF函数的可用的解决方案为:
在Excel 2010及以上版本,可以利用C/C++调用Excel API,开发XLL类型插件实现。
在Excel2002 及以上版本,可以利用Excel RTD函数,来实现
通过第三方类库,如Excel-DNA中引入的ReactiveExtension来实现。
&& 考虑到Excel个版本最大限度的兼容性以及本系列文章主要关注.NET 下的Excel插件开发,所以将重点介绍第2种方法。
二 如何使用RTD实现异步UDF
&&& ,RTD函数主要是用来作为实时数据更新来使用的,但是我们可以利用RTD函数的这种特殊的Push-Pull机制来开发异步的UDF函数。异步UDF函数的主要实现框架如下图:
基于RTD的异步UDF函数的实现大致流程如上:
用户输入UDF函数,在VBA函数层面上,将UDF函数的函数名,及参数作为RTD函数的参数数组,在内部发起RTD函数调用。
在RTD函数的ConnectData方法中,将该次请求Excel分配的TopicID,以及请求的参数,包括函数名,参数拼接成Formula的样式,作为Key保存到一个全局的Dictionary中,Value为一个实体类,该实体类记录了此次的TopicID,以及该Key的请求返回的值Result(Object类型的)以及其他一些字段。
ConnectData返回Loading,或者其他提示符,在单元格中显示,提示正在后台运算。
同时,另开一个线程对全局的请求Dictionary里面的请求进行处理,这个过程涉及到同步的处理,因为有可能在处理请求的时候,又有新的请求添加进来。
取出key,解析方法名及参数,使用反射或者一些高效率的方法获取该请求对应的值,存储到key对应的Value的实体的Result字段中。
同时调用RTD的UpdateNotify方法,通知Excel有数据要更新。
Excel调用RTD的RefreshData方法,然后将全局请求的Dictionary中有结果值的数据项及TopicID,放到二维数组中,并返回。
Excel单元格显示为该请求实际返回的结果值。
&&& 下面就按照以上的逻辑编写一个简单的异步UDF的实现。
1. 实现UDF集中处理实体类
&&& 在最开始之前,我们要定义一个基于Dictionary自定义一个RequestDictionary实体类,用于存储所有的请求以及请求结果,该类继承自Dictionary&String, Request&并实现了IDictionary&string, Request&方法。
internal sealed class RequestsDictionary : Dictionary&String, Request&, IDictionary&string, Request&
&&& 在该类中,我们定义了一个枚举型的状态变量,分为Idle,Processing,Waiting三个状态,并定义了一个一步集合AsyncList,用来保存与处理的请求集合。
private AsyncList&Request& processRequestC
private int
public int State { get { return
&&& 然后,我们的实例内部,对pocessRequestCollection进行处理,处理完成之后,回调 RequestProcessCompletedHandle事件。
public event EventHandler&ProcessCompletedArgs& RequestProcessCompletedH
&&& 我们重写了该类的Add方法,当在RTD中往该实体类中添加请求时:
public new void Add(string key, Request value)
if (!base.ContainsKey(key))
base[key] =
if (Interlocked.Exchange(ref this.state, (int)ProcessState.Waiting) == (int)ProcessState.Idle)
this.processRequestCollection.Add(value);
OnRequestAdded(null);
Interlocked.Exchange(ref this.state, (int)ProcessState.Waiting);
this.processRequestCollection.Add(value);
&&& 如果当前状态属于空闲,则将请求加载到待处理集合中,并将状态改为等待,并发起请求处理命令。后面如果有请求过来了,直接添加到待处理集合中。而不再次发起处理请求,只有当前状态变为idle了才会再次对集合中的待处理命令进行处理。
private void OnRequestAdded(Request[] formulas)
RequestProcessor processor = new RequestProcessor(realProcessMethod);
string[] refeshedF
processor.BeginInvoke(formulas, out refeshedFormulas, new AsyncCallback(RequestProcessCompletedCallback), processor);
&&& 在OnRequestAdd方法中,我们使用异步代理,发起了一个真正的对请求处理的方法realProcessMethod方法。该方法的实现如下:
bool realProcessMethod(Request[] request, out string[] refeshedIds)
if (request == null)
Thread.Sleep(10);
refeshedIds = null;
return true;
List&string& requestList = new List&string&(request.Length);
refeshedIds = new string[request.Length];
for (int i = 0; i & request.L i++)
requestList.Add(request[i].Formula);
refeshedIds[i] = request[i].F
//GetValues method get the proc
Dictionary&string, object& dictionaryWithValues = GetValues(requestList);
Request requestI
foreach (KeyValuePair&string, Object& item in dictionaryWithValues)
requestInstance = this[item.Key];
requestInstance.Result = item.V
requestInstance.InCache = true;
return true;
refeshedIds = null;
return false;
&&& 该方法中,我们所有请求的ID放到refreshId中,当计算完成之后,我们就可以通知Excel仅刷新这些refreshId的数据了。方法中,我们真正处理请求的是在GetValue方法中,该方法接受所有请求的表达式,然后返回以该表达式为key,结果值为value的Dictionary对象。这里为了演示,我们让每个方法请求睡眠1秒,以模拟耗时操作,并直接返回函数中的参数作为返回值。在真实的场景中,我们通常将requestList拿出来解析,解析出函数名词,函数参数,然后利用反射,或者是约定的处理方式对这些请求进行计算并求得结果,就拿前面我们看过的天气预报的例子来说,如果用户在Excel中输入 =YY_Weather_Condition(&Shanghai&, &&),那么我们的requestList中就有一个名为 =YY_Weather_Condition(&Shanghai&, &&)的字符串,解析第一部分,就知道是函数名称,括号里面的就是参数, 然后动态的去调用相应的方法,或者直接对该逻辑进行判断处理,一般滴,我们的函数都是约定好的,所以可以直接采用if的方式进行判断然后进行处理。
bool realProcessMethod(Request[] request, out string[] refeshedIds)
if (request == null)
Thread.Sleep(10);
refeshedIds = null;
return true;
List&string& requestList = new List&string&(request.Length);
refeshedIds = new string[request.Length];
for (int i = 0; i & request.L i++)
requestList.Add(request[i].Formula);
refeshedIds[i] = request[i].F
//GetValues method get the proc
Dictionary&string, object& dictionaryWithValues = GetValues(requestList);
Request requestI
foreach (KeyValuePair&string, Object& item in dictionaryWithValues)
requestInstance = this[item.Key];
requestInstance.Result = item.V
requestInstance.InCache = true;
return true;
refeshedIds = null;
return false;
&&& 本例中,我们对之前的天气函数进行改造,将其改造为异步的UDF,所以这里的GetValue方法我们去获取天气情况:
//Fake method
//获取天气情况
private Dictionary&string, object& GetValues(List&string& requestList)
Dictionary&string, object& results = new Dictionary&string, object&();
for (int i = 0; i & requestList.C i++)
string request = requestList[i];
string functionName = request.Substring(0, request.LastIndexOf('('));
string[] parameters = request.Substring(request.LastIndexOf('(') + 1, request.Length - request.LastIndexOf('(') - 2).Split(',');
Object returnValue = "Paramters Error!";
//Thread.Sleep(1000);
if (functionName.Equals("YY_Weather_Condition") ||
functionName.Equals("YY_Weather_Temperature") ||
functionName.Equals("YY_Weather_WindSpeed"))
if (parameters.Length == 2)
string city = parameters[0];
string date = parameters[1];
returnValue = GetWeather(functionName, city, date);
else //return parameters
returnValue = request.Substring(request.LastIndexOf(','));
results.Add(requestList[i], returnValue);
private Object GetWeather(string functionName, string city, string date)
Object result = null;
Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
switch (functionName)
case "YY_Weather_Condition":
result = weather.Condition.T
case "YY_Weather_Temperature":
result = weather.Condition.T
case "YY_Weather_WindSpeed":
result = weather.Wind.S
&&& 该方法执行完成之后,会调用RequestProcessCompletedCallback这个回调方法, 在该回调方法中:
void RequestProcessCompletedCallback(IAsyncResult asyncResult)
RequestProcessor processor = (RequestProcessor)asyncResult.AsyncS
string[] refeshedF
bool isCompleted = processor.EndInvoke(out refeshedFormulas, asyncResult);
if (isCompleted)
if (Interlocked.Exchange(ref this.state, (int)ProcessState.Idle) == (int)ProcessState.Waiting)
Interlocked.Exchange(ref this.state, (int)ProcessState.Processing);
OnRequestAdded(this.processRequestCollection.PopupRest());
// which means no entry added yet
this.processRequestCollection.Clear();
OnRequestCompleted(new ProcessCompletedArgs(refeshedFormulas));
private void OnRequestCompleted(ProcessCompletedArgs args)
if (this.RequestProcessCompletedHandle != null)
this.RequestProcessCompletedHandle(this, args);
&&& 我们查看当前的状态, 如果当前处于等待状态,则将状态改为空闲表示我们的已经处理完了。 然后将后面添加的请求继续进行处理,否则,表示所有的请求都处理完了,清空本地的待处理的请求队列。最后调用回调方法,传入待刷新的单元格formulas通知Excel刷新相应的单元格。
&&& 该类是异步UDF 的核心处理逻辑, 因为要涉及到不停的处理所有添加的请求,对请求集合的处理,一边在添加,一边在读取处理,为了减轻加锁对系统性能造成的影响,方法中大量使用了无锁编程的技巧,这一点对于提升性能有很大帮助,详细使用方法在后面讲到性能优化的时候我会再写一篇文章详细讲解,当然了,在CLR Via C# 4th中对该技术有详细的介绍。为了实现该类能够对请求进行不停的处理,将之前的使用timer控件的定时检查,然后处理逻辑,转换成了效率更高的三状态处理机制,极大的提高了性能和响应性。
&&& 写完了我们的请求处理类之后,我们需要在RTD 函数中对接收的请求进行统一的处理。和文章介绍如何创建RTD函数一样,我们新建一个RTD的类,然后实现IRtdServer接口及相应的方法。
2. 对RTD 函数进行改造
第一部分写完处理函数之后,接下来需要编写RTD 函数了,将普通的函数请求添加到之前的处理类中来。如何创建RTD 函数这里就不多讲了,您可以直接看的文章,这里不再赘述。
[Guid("BB007B7A--A230-0CD8A2BDD489")]
[ProgId("YYAsyncRTD.Func")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class YYAsyncRTD : IRtdServer
private SynchronizationContext ExcelC
private static RequestsDictionary Requests = new RequestsDictionary();
private static IRTDUpdateEvent xlRTDU
public int ServerStart(IRTDUpdateEvent CallbackObject)
this.ExcelContext = new SynchronizationContext();
xlRTDUpdater = CallbackO
Requests.RequestProcessCompletedHandle += new EventHandler&ProcessCompletedArgs&(Requests_RequestProcessCompletedHandle);
public void ServerTerminate()
Requests.Clear();
xlRTDUpdater = null;
&&& 首先我们定义了三个对象,RequestsDictionary类型的Requests对象用来存储和处理所有传进来的请求,IRTDUpdateEvent对象用来保存ServerStart中的CallBack对象,用于后面调用UpdateNotify方法。这里还定义了一个同步上下文环境,用来保存Excel主线程的上下文环境,因为我们再调用RTD的UpdateNotify方法时,必须在主线程上操作。
&&& 在ServerStart函数中,我们注册了RequestsDictionary对象的处理完成事件。在该回调方法中我们向Excel发出消息,提示调用UpdateNotify方法:
void Requests_RequestProcessCompletedHandle(object sender, ProcessCompletedArgs e)
if (e.Formulas != null && e.Formulas.Length != 0)
ExcelContext.Send(delegate(object obj) { xlRTDUpdater.UpdateNotify(); }, null);
一切初始化好之后,我们开始编写ConnectData方法:
public dynamic ConnectData(int TopicID, ref Array Strings, ref bool GetNewValues)
string formula = GetFormula(Strings);
Request tmpR
if (Requests.ContainsKey(formula))
tmpRequest = Requests[formula];
tmpRequest.IsValid = true;
if (tmpRequest.InCache)
return tmpRequest.Result.ToString();
return "Fetching...";
Request requestObj = new Request();
requestObj.Formula =
requestObj.TopicID = TopicID;
requestObj.InCache = false;
requestObj.IsValid = true;
Requests.Add(formula, requestObj);
return "Fetching...";
&&& 在该方法中,我们对于每一个请求,新建了一个Request对象,并将该请求的TopicID,formula记下来,然后加入到处理集合中,然后返回Processing& 提示用户后台正在处理。
&&& 在Refresh方法中,我们遍历集合中所有已经处理完成了的请求,然后赋给二维数组返回供Excel刷新使用:
public Array RefreshData(ref int TopicCount)
object[,] valueArray = new object[2, Requests.Count];
int count = 0;
foreach (Request item in Requests.Values)
if (item.IsValid && item.InCache)
valueArray[0, count] = item.TopicID;
valueArray[1, count++] = item.R
TopicCount =
return valueA
&&& 在Refresh方法中,我们遍历集合中所有已经处理完成了的请求,然后赋给二维数组返回供Excel刷新使用。
&&& 现在我们的RTD 函数写完了,用户如果要查询天气,输入=YY_Weather_Condition(&Shanghai&, &&),我们可以在VBA中发起响应的RTD 调用=RTD(&YYAsyncRTD.Func&,,&YY_Weather_Condition&,&2&,&Shanghai&,& &),我们约定RTD中,第一个参数为函数名称,第二个参数为该函数的参数个数,后面的都是函数的具体参数。这样我们就可以在请求的逻辑处还原YY_Weather_Condition(&Shanghai&, &&)这一请求。这样我们的函数就是异步的UDF 函数了。
3. 实际效果
&&& 写完上面的实现之后,将该项目设置为面向com可见,然后编译整个类库,我们在该RTD中可以异步调用我们之前的天气函数了。比如我们可以在单元格中输入函数:
=RTD("YYAsyncRTD.Func",,"YY_Weather_Condition",2, "Shanghai",TODAY())
&&& 该函数首先返回Fetching通知Excel正在处理,然后待处理完成之后,将Shanghai今天的天气情况刷新返回出来。我录制了一个动画,效果如下:
&&& 可以看到,整个用户界面要比同步的UDF函数要好很多,而且在单元格Fetching的时候,Excel单元格还是能够响应其他的操作,比如选中其他单元格等等,Excel的UI界面一点儿没有阻塞。
&&& 本文首先介绍了异步自定义函数相较于传统的同步UDF的具有良好扩展性,用户体验等优点,然后介绍了在Excel中实现异步UDF的步骤及解决方案,最后通过自定义Dictionary类,然后基于RTD函数实现了一个简单的异步UDF函数,并通过该异步UDF函数实现了对第四篇文章中的天气函数的调用。
&&& 本文所有代码点击下载,Excel 异步UDF函数编写较为复杂,希望本文对您了解及如何编写Excel异步UDF函数有所帮助。
阅读(...) 评论()查看:8915|回复:6
从身份证号中提出出生日期
我们可以使用Excel常用函数来提出身份证号码中的出生日期,然而在输入身份证号码的时候出现一个问题,当输入身份证号码为:148765时,此时出现下面的情况:
后面百度才发现原因是——excel中超过15位的数字在一个单元格里都不能完全显示,所以解决这个问题的办法就是把身份证号以文本形式存储,有两种方式实现以文本方式存储:
方法1: 先选择单元格,再右键选择&设置单元格格式& ,在弹出的窗体中选择文本
再输入身份证号
方法2: 在身份证号前输入一个( ' )这个符号,这个符号代表就是把身份证号作为文本方式存储
我之前根本是不知道上面的问题的,所以拿出来分享出来。下面当我们输入了正确的身份证号之后,如何使用Excel公式获得出生日期呢?
这里要用到下面公式:
(1)TEXT函数(类似C#中的Tostring方法)
功能:根据指定的数据格式将相应的数字转化为文本形式
格式为:TEXT(value, format)
参数说明: value代表需要转换的数值或引用的单元格;format表示为指定文字形式的数字格式
(2) MID函数(类似C#中的Substring)
功能:从一个文本字符串的指定位置开始,截取指定数目的字符
格式:MID(text,start,num_chars)
参数说明:text代表一个文本字符串或引用的单元格。start表示指定的开始位置,num_chars表示要截取的字符个数
函数名称:DATEDIF 
功能:计算返回两个日期参数的差值。  
格式:=DATEDIF(date1,date2,&y&)、=DATEDIF(date1,date2,&m&)、=DATEDIF(date1,date2,&d&)  
参数说明:date1代表前面一个日期,date2代表后面一个日期;y(m、d)要求返回两个日期相差的年(月、天)数。
LEN函数  
函数名称:LEN 
功能:统计文本字符串中字符数目。  
格式:LEN(text)  
参数说明:text表示要统计的文本字符串。
下面就使用这个两个函数来提取出生日期:
从身份证中获得出生日期的的函数公式为: =TEXT(MID(A1,7,6+(LEN(A1)=18)*2),&#-00-00&) 其中Len(A1)=18*2 代表的意思是如何A1的长度是18位的话,就 1*2,否则就是 0*2(Len(A1)=18相当于一个逻辑判断,当A1单元格的值的字符个数等于18时,则返回True,即为1,否则返回false,即为0),有了这个公式之后我们可以用拖动的方式来计算单元格中所有身份证号的出生日期
下面再附上从身份证号码中获得年龄的公式:&&=DATEDIF(TEXT(MID(A1,7,6+(LEN(A1)=18)*2),&#-00-00&),TODAY(),&y&)&&岁&
感谢分享!
本帖最后由 LearningHard 于
01:53 编辑
先自己帮自己顶一个,让大家知道Excel中函数帮我们实现的功能。
这一个好,楼主好像函数玩得不错哦
~Near.~一个人,要是不逼自己一把,根本不知道自己有多优秀
:lol1 ,感觉挺不错的,学习了
引用:原帖由 Nico_Lv 于
20:35 发表
这一个好,楼主好像函数玩得不错哦 嘿嘿,版主过奖了,只是拿出来和大家分享下,因为觉得朋友们平时可能使用Excel的时候可能没有对Excel函数了解,掌握Excel的函数可以更方便的操作Excel表格,所以拿出来分享,希望受益更多人
引用:原帖由 fanmiaofu 于
20:40 发表
:lol1 ,感觉挺不错的,学习了 嗯,如果好的话,可以帮忙在微博中分享下的,让更多的朋友来学习
一看楼主就是搞开发的,用的函数比我的强多了。复制内容到剪贴板代码:=TEXT(IF(LEN(A2)=18,MID(A2,7,8),19&MID(A2,7,6)),&00-00-00&)}

我要回帖

更多关于 c实现打印调用栈 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信