在Excel催化剂中,大量的自定义函数使用了动态数组函数效果,虽然不是原生的Excel365版效果(听说Excel2019版取消了支持动态数组函数,还没求证到位,Excel365是可以用,但也仅限于部分尝鲜用户可以用上,大部分Excel365用户还没推送成功),但对于自定义函数这条路线,可以实现类似效果,已经是非常震撼及使用面非常广大了。

顺便插一句,不是每个中国企业都能承担起高昂的软件更新费用,OFFICE软件非常大的一个坑爹之处是,旧版本升级到新版本,没有补差价升级一说,一律是重新购买,旧的也不能转让其他公司使用(这个没求证过,有错误请指出)。

在这样的OFFICE政策下,让企业每三年紧追OFFICE新版本给员工配置,这个可是极大的软件费用负担和软件使用浪费。

现在中美关系紧张,中国知识产权问题也是摆上台面要考虑的事情,不能动不动类似个人一样可以用盗版软件,企业用的软件是需要购买授权使用的,同样的Excel催化剂也只是对个人用户免费使用,企业用户没有任何承诺过免费使用一说。

在这样的情形下,如果我们能够通过自定义函数的方式,扩展一下原有旧版本的功能,使用户们不必垂帘新OFFICE版本功能而没法使用的打击学习热情,也可以有替代方案完成,间接也帮助企业节省软件成本,为国家减少盗版问题的贸易摩擦,上升高一层,是一种爱国行为了。

动态数组函数实现手段

借助ExcelDna框架来开发自定义函数,其作者也为我们准备了动态数组函数的技术实现,具体原理对于笔者这样的重业务导向的,也不懂其中的高深技术,有兴趣的朋友们可以深入研究后再更多分享出来。

在Excel自定义函数中,例如GetFiles函数,通过简单的.Net的IO类,实现遍历文件夹里的所有文件的功能,返回一个文件全路径的数组。

最终的关键技术是,如何让返回的这个数组结果,在用户在一个单元格中输入函数时,自动对其返回的多个结果进行单元格区域自动扩张,并以数组函数的方式返回。

 
GetFiles函数实现效果

具体代码

在GetFiles函数中,关键代码为最后将files数组返回到工作表结果的方法。

Common.ReturnDataArray(files, optAlignHorL);

  1. [ExcelFunction(Category = "文件文件夹相关", Description = "获取指定目录下的文件清单,srcFolder为传入的顶层目录,containsText可用作筛选包含containsText内容的文件夹,isSearchAllDirectory为是否查找顶层目录下的文件夹的所有子文件夹。Excel催化剂出品,必属精品!")]
  2. public static object GetFiles(
  3. [ExcelArgument(Description = "传入的顶层目录,最终返回的结果将是此目录下的文件夹或子文件夹下的全路径文件名")] string srcFolder,
  4. [ExcelArgument(Description = "查找的文件名中是否需要包含指定字符串,不传参数默认为返回所有文件,可传入复杂的正则表达式匹配。")] string containsText,
  5. [ExcelArgument(Description = "是否查找顶层目录下的文件夹的所有子文件夹,TRUE和非0的字符或数字为搜索子文件夹,其他为否,不传参数时默认为否")] object isSearchAllDirectory,
  6. [ExcelArgument(Description = "返回的结果是按按列排列还是按行排列,传入L按列排列,传入H按行排列,不传参数或传入非L或H则默认按列排列")] string optAlignHorL)
  7. {
  8. string[] files;
  9. if (Common.IsMissOrEmpty(containsText))
  10. {
  11. containsText = string.Empty;
  12. }
  13. //当isSearchAllDirectory为空或false,默认为只搜索顶层文件夹
  14. if (Common.IsMissOrEmpty(isSearchAllDirectory) || Common.TransBoolPara(isSearchAllDirectory) == false)
  15. {
  16. files = Directory.EnumerateFiles(srcFolder).Where(s => isContainsText(Path.GetFileName(s), containsText)).ToArray();
  17. }
  18. else
  19. {
  20. files = Directory.EnumerateFiles(srcFolder, "*", SearchOption.AllDirectories).Where(s => isContainsText(Path.GetFileName(s), containsText)).ToArray();
  21. }
  22. return Common.ReturnDataArray(files, optAlignHorL);
  23. }

拆解此方法可知,其实最关键的部分已经出来了
return ArrayResizer.Resize(resultArr);

  1. public static object ReturnDataArray(object[] srcArrData, string optAlignHorL)
  2. {
  3. int resultCount = srcArrData.Count();
  4. if (Common.IsMissOrEmpty(optAlignHorL) || optAlignHorL.Equals("H", StringComparison.CurrentCultureIgnoreCase) == false)
  5. {
  6. optAlignHorL = "L";
  7. }
  8. else
  9. {
  10. optAlignHorL = "H";
  11. }
  12. //直接用从下标为0开始的数组也可以
  13. if (optAlignHorL == "L")
  14. {
  15. object[,] resultArr = new object[resultCount, 1];
  16. for (int i = 0; i < resultCount; i++)
  17. {
  18. resultArr[i, 0] = srcArrData[i];
  19. }
  20. //return resultArr;
  21. return ArrayResizer.Resize(resultArr);
  22. }
  23. else
  24. {
  25. //横排时,直接用一维数组就可以识别到
  26. object[,] resultArr = new object[1, resultCount];
  27. for (int i = 0; i < resultCount; i++)
  28. {
  29. resultArr[0,i] = srcArrData[i];
  30. }
  31. return ArrayResizer.Resize(resultArr);
  32. }
  33. }

最后贴上这个帮助类的源代码,是从ExcelDna作者的示例代码中抄过来的,笔者是看不懂的,但确实是起作用了,用了异步函数的方法返回结果。

  1. using ExcelDna.Integration;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. namespace ExcelCuiHuaJi
  7. {
  8. public class ArrayResizer : XlCall
  9. {
  10. // This function will run in the UDF context.
  11. // Needs extra protection to allow multithreaded use.
  12. internal static object Resize(object[,] array)
  13. {
  14. var caller = Excel(xlfCaller) as ExcelReference;
  15. if (caller == null)
  16. return array;
  17. int rows = array.GetLength(0);
  18. int columns = array.GetLength(1);
  19. if (rows == 0 || columns == 0)
  20. return array;
  21. if ((caller.RowLast - caller.RowFirst + 1 == rows) &&
  22. (caller.ColumnLast - caller.ColumnFirst + 1 == columns))
  23. {
  24. // Size is already OK - just return result
  25. return array;
  26. }
  27. var rowLast = caller.RowFirst + rows - 1;
  28. var columnLast = caller.ColumnFirst + columns - 1;
  29. // Check for the sheet limits
  30. if (rowLast > ExcelDnaUtil.ExcelLimits.MaxRows - 1 ||
  31. columnLast > ExcelDnaUtil.ExcelLimits.MaxColumns - 1)
  32. {
  33. // Can't resize - goes beyond the end of the sheet - just return #VALUE
  34. // (Can't give message here, or change cells)
  35. return ExcelError.ExcelErrorValue;
  36. }
  37. // TODO: Add some kind of guard for ever-changing result?
  38. ExcelAsyncUtil.QueueAsMacro(() =>
  39. {
  40. // Create a reference of the right size
  41. var target = new ExcelReference(caller.RowFirst, rowLast, caller.ColumnFirst, columnLast, caller.SheetId);
  42. DoResize(target); // Will trigger a recalc by writing formula
  43. });
  44. // Return what we have - to prevent flashing #N/A
  45. return array;
  46. }
  47. //public static double[,] ResizeDoubles(double[,] array)
  48. //{
  49. // var caller = Excel(xlfCaller) as ExcelReference;
  50. // if (caller == null)
  51. // return array;
  52. // int rows = array.GetLength(0);
  53. // int columns = array.GetLength(1);
  54. // if (rows == 0 || columns == 0)
  55. // return array;
  56. // if ((caller.RowLast - caller.RowFirst + 1 == rows) &&
  57. // (caller.ColumnLast - caller.ColumnFirst + 1 == columns))
  58. // {
  59. // // Size is already OK - just return result
  60. // return array;
  61. // }
  62. // var rowLast = caller.RowFirst + rows - 1;
  63. // var columnLast = caller.ColumnFirst + columns - 1;
  64. // if (rowLast > ExcelDnaUtil.ExcelLimits.MaxRows - 1 ||
  65. // columnLast > ExcelDnaUtil.ExcelLimits.MaxColumns - 1)
  66. // {
  67. // // Can't resize - goes beyond the end of the sheet - just return null (for #NUM!)
  68. // // (Can't give message here, or change cells)
  69. // return null;
  70. // }
  71. // // TODO: Add guard for ever-changing result?
  72. // ExcelAsyncUtil.QueueAsMacro(() =>
  73. // {
  74. // // Create a reference of the right size
  75. // var target = new ExcelReference(caller.RowFirst, rowLast, caller.ColumnFirst, columnLast, caller.SheetId);
  76. // DoResize(target); // Will trigger a recalc by writing formula
  77. // });
  78. // // Return what we have - to prevent flashing #N/A
  79. // return array;
  80. //}
  81. static void DoResize(ExcelReference target)
  82. {
  83. // Get the current state for reset later
  84. using (new ExcelEchoOffHelper())
  85. using (new ExcelCalculationManualHelper())
  86. {
  87. ExcelReference firstCell = new ExcelReference(target.RowFirst, target.RowFirst, target.ColumnFirst, target.ColumnFirst, target.SheetId);
  88. // Get the formula in the first cell of the target
  89. string formula = (string)Excel(xlfGetCell, 41, firstCell);
  90. bool isFormulaArray = (bool)Excel(xlfGetCell, 49, firstCell);
  91. if (isFormulaArray)
  92. {
  93. // Select the sheet and firstCell - needed because we want to use SelectSpecial.
  94. using (new ExcelSelectionHelper(firstCell))
  95. {
  96. // Extend the selection to the whole array and clear
  97. Excel(xlcSelectSpecial, 6);
  98. ExcelReference oldArray = (ExcelReference)Excel(xlfSelection);
  99. oldArray.SetValue(ExcelEmpty.Value);
  100. }
  101. }
  102. // Get the formula and convert to R1C1 mode
  103. bool isR1C1Mode = (bool)Excel(xlfGetWorkspace, 4);
  104. string formulaR1C1 = formula;
  105. if (!isR1C1Mode)
  106. {
  107. object formulaR1C1Obj;
  108. XlReturn formulaR1C1Return = TryExcel(xlfFormulaConvert, out formulaR1C1Obj, formula, true, false, ExcelMissing.Value, firstCell);
  109. if (formulaR1C1Return != XlReturn.XlReturnSuccess || formulaR1C1Obj is ExcelError)
  110. {
  111. string firstCellAddress = (string)Excel(xlfReftext, firstCell, true);
  112. Excel(xlcAlert, "Cannot resize array formula at " + firstCellAddress + " - formula might be too long when converted to R1C1 format.");
  113. firstCell.SetValue("'" + formula);
  114. return;
  115. }
  116. formulaR1C1 = (string)formulaR1C1Obj;
  117. }
  118. // Must be R1C1-style references
  119. object ignoredResult;
  120. //Debug.Print("Resizing START: " + target.RowLast);
  121. XlReturn formulaArrayReturn = TryExcel(xlcFormulaArray, out ignoredResult, formulaR1C1, target);
  122. //Debug.Print("Resizing FINISH");
  123. // TODO: Find some dummy macro to clear the undo stack
  124. if (formulaArrayReturn != XlReturn.XlReturnSuccess)
  125. {
  126. string firstCellAddress = (string)Excel(xlfReftext, firstCell, true);
  127. Excel(xlcAlert, "Cannot resize array formula at " + firstCellAddress + " - result might overlap another array.");
  128. // Might have failed due to array in the way.
  129. firstCell.SetValue("'" + formula);
  130. }
  131. }
  132. }
  133. }
  134. // RIIA-style helpers to deal with Excel selections
  135. // Don't use if you agree with Eric Lippert here: http://stackoverflow.com/a/1757344/44264
  136. public class ExcelEchoOffHelper : XlCall, IDisposable
  137. {
  138. object oldEcho;
  139. public ExcelEchoOffHelper()
  140. {
  141. oldEcho = Excel(xlfGetWorkspace, 40);
  142. Excel(xlcEcho, false);
  143. }
  144. public void Dispose()
  145. {
  146. Excel(xlcEcho, oldEcho);
  147. }
  148. }
  149. public class ExcelCalculationManualHelper : XlCall, IDisposable
  150. {
  151. object oldCalculationMode;
  152. public ExcelCalculationManualHelper()
  153. {
  154. oldCalculationMode = Excel(xlfGetDocument, 14);
  155. Excel(xlcOptionsCalculation, 3);
  156. }
  157. public void Dispose()
  158. {
  159. Excel(xlcOptionsCalculation, oldCalculationMode);
  160. }
  161. }
  162. // Select an ExcelReference (perhaps on another sheet) allowing changes to be made there.
  163. // On clean-up, resets all the selections and the active sheet.
  164. // Should not be used if the work you are going to do will switch sheets, amke new sheets etc.
  165. public class ExcelSelectionHelper : XlCall, IDisposable
  166. {
  167. object oldSelectionOnActiveSheet;
  168. object oldActiveCellOnActiveSheet;
  169. object oldSelectionOnRefSheet;
  170. object oldActiveCellOnRefSheet;
  171. public ExcelSelectionHelper(ExcelReference refToSelect)
  172. {
  173. // Remember old selection state on the active sheet
  174. oldSelectionOnActiveSheet = Excel(xlfSelection);
  175. oldActiveCellOnActiveSheet = Excel(xlfActiveCell);
  176. // Switch to the sheet we want to select
  177. string refSheet = (string)Excel(xlSheetNm, refToSelect);
  178. Excel(xlcWorkbookSelect, new object[] { refSheet });
  179. // record selection and active cell on the sheet we want to select
  180. oldSelectionOnRefSheet = Excel(xlfSelection);
  181. oldActiveCellOnRefSheet = Excel(xlfActiveCell);
  182. // make the selection
  183. Excel(xlcFormulaGoto, refToSelect);
  184. }
  185. public void Dispose()
  186. {
  187. // Reset the selection on the target sheet
  188. Excel(xlcSelect, oldSelectionOnRefSheet, oldActiveCellOnRefSheet);
  189. // Reset the sheet originally selected
  190. string oldActiveSheet = (string)Excel(xlSheetNm, oldSelectionOnActiveSheet);
  191. Excel(xlcWorkbookSelect, new object[] { oldActiveSheet });
  192. // Reset the selection in the active sheet (some bugs make this change sometimes too)
  193. Excel(xlcSelect, oldSelectionOnActiveSheet, oldActiveCellOnActiveSheet);
  194. }
  195. }
  196. }

结语

以上涉及的所有代码已经进行开源,并且整个自定义函数项目也已经开源了,甚至不需要重新开项目,重新复制粘贴,直接在源项目上增删内容,即可完成自定义函数的开发,Excel催化剂开源作贡献是认真的。

通过动态数组函数技术开发自定义函数,不必再烦恼于用户不懂数组函数的复杂输入方式及数组函数返回结果不确定时,不知道该选定多少单元格的烦恼。也不必羡慕Excel365用户可以用上的动态数组函数,在Excel自定义函数中,比官方提供的函数使用场景更广,门槛列低,通用性更强,在Excel2007及以后所有版本都可使用,方便作文件的分享。

技术交流QQ群

QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

 
Excel催化剂开源讨论群二维码

关于Excel催化剂

Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!

Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!

Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q

 
联系作者
 
公众号

取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。

最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!

关于Excel催化剂作者

姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)

技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。

擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。

2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。

和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。

技术交流QQ群

QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

 
Excel催化剂开源讨论群二维码

关于Excel催化剂

Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!

Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!

Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q

 
联系作者
 
公众号

取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。

最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!

关于Excel催化剂作者

姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)

技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。

擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。

2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。

和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。

Excel催化剂开源第11波-动态数组函数技术开源及要点讲述的更多相关文章

  1. 个人永久性免费-Excel催化剂功能第46波-区域集合函数,超乎所求所想

    在常规自定义函数的世界中,一般情况下,仅会输入一堆的参数,最终输出一个结果值,在以往Excel催化剂的自定义函数,已经大量出现输入一堆参数返回多个结果值并自动输出到多个单元格区域内.此项技术可运用的场 ...

  2. 个人永久性免费-Excel催化剂功能第36波-新增序列函数用于生成规律性的循环重复或间隔序列

    啃过Excel函数的表哥表姐们,一定对函数的嵌套.数组公式等高级的应用有很深的体会,威力是大,但也烧死不少脑细胞,不少人就在这样的绕函数中光荣地牺牲了,走向从入门到放弃.Excel催化剂的创立,初衷就 ...

  3. 个人永久性免费-Excel催化剂功能第20波-Excel与Sqlserver零门槛交互-数据上传篇

    Excel作为众多数据存储的交换介质,在不同的系统内的数据很少可以很连贯地进行整合分析,一般的业务系统都会提供导出Excel作为标配功能供用户使用系统内生成的数据. 此时最大的问题是,Excel很维去 ...

  4. 个人永久性免费-Excel催化剂功能第19波-Excel与Sqlserver零门槛交互-查询篇

    对频繁使用Excel的高级应用的尝试用户来说,绕不过的一个问题Excel的性能问题,对于几万条数据还说得过去,上了10万行的数据量,随便一个函数公式的运算都是一个不小的负荷,有些上进一点的用户会往Ac ...

  5. 个人永久性免费-Excel催化剂功能第18波-在Excel上也能玩上词云图

    这年头数据可视化日新月异,在Excel上做数据分析,最后一步,难免要搞个图表输出高大上一回,微软也深知此道,在Excel2016上更新了一大波图表功能,市场上很耀眼的词云图还是没加进来,虽然在各大的在 ...

  6. 个人永久性免费-Excel催化剂功能第17波-批量文件改名、下载、文件夹创建等

    前几天某个网友向我提出催化剂的图片功能是否可以增加导出图片功能,这个功能我一直想不明白为何有必要,图片直接在电脑里设个文件夹维护着不就可以了么?何苦还要把Excel上的图片又重新导出到文件夹中?这个让 ...

  7. 个人永久性免费-Excel催化剂功能第16波-N多使用场景的多维表转一维表

    Excel表的多维表数据结构转换为一维表的数据结构,以供更进一步对数据进行加工整理,生成另外格式的汇总表,这是Excel数据处理的一大刚需,几乎每个Excel表哥.表姐都会遇到这样的使用场景.很可惜, ...

  8. 个人永久性免费-Excel催化剂功能第101波-批量替换功能(增加正则及高性能替换能力)

    数据处理无小事,正如没有人活在真空理想环境一下,在数据分析过程中,也没有那么真空理想化的数据源可以使用,数据处理占据数据分析的80%的时间,每一个小小的改善,获益都良多.Excel查找替换,有其局限性 ...

  9. 个人永久性免费-Excel催化剂功能第99波-手机号码归属地批量查询

    高潮过往趋于平静,送上简单的手机号码归属地查询,因接口有数量限制,仅能满足少量数据需求,如有大规模数据却又想免费获得,这就成为无解了,数据有价,且用且珍惜. 业务使用场景 除了日常自带的手机各种管家为 ...

随机推荐

  1. 通过异步程序调用(APC)实现的定时功能

    定时器是一个在特定时间或者规则间隔被激发的内核对象.结合定时器的异步程序调用可以允许回调函数在任何定时器被激发的时候执行.本文的例子代码显示了如何实现. 使用本定时器时,你需要把常量_WIN32_WI ...

  2. css的圣杯布局

    圣杯布局和双飞翼布局实现的效果是一样的. 代码解析: 1.四个section,container,main,left,right.其中那个container为父容器. 2.main,left,righ ...

  3. 从IntToHex()说起,栈/堆地址标准写法 good

    学习中的一些牢骚.栈/堆地址标准写法. 2017-02-12 • 杂谈 • 暂无评论 • 老衲 •浏览 226 次 我一直都在寻找各种业务功能的最简单写法,用减法的模式来开发软件.下面是我的写法,如果 ...

  4. Qt之Model-View架构(雨田哥的博客)

    Qt之Model-View架构 Qt之Model-View架构 简述 效果图 代码 结尾 简述 为什么会用这个模式,这里我就不解释了,可以看下 豆子哥的见解 .这里我只是如何去使用的.供大家共同探讨学 ...

  5. vista下开机启动 简单绕过UAC的方法(自己使用runas参数重新启动自己,有点意思)

    背景      vista下,如果不开启UAC,那就没有我下面要说的问题了,呵呵.下面说的都是在vista开启UAC的前提下说的,win7也适用.      在vista下,系统开启了UAC,如果你的 ...

  6. ab fails to connect to localhost

    The following command fails: $ ab -n 1 localhost:8000/ ... Benchmarking localhost (be patient)...apr ...

  7. mysql查询类型转换问题

    mysql转换类型.类型转换.查询结果类型转换 一.问题来源 数据库一张表的主键id设为了自增,那就是int型的,但是其他表的关联字段又设置成了字符串! 而且已经开发了很久才发现问题,既然出现了问题肯 ...

  8. Spark学习之路(五)—— Spark运行模式与作业提交

    一.作业提交 1.1 spark-submit Spark所有模式均使用spark-submit命令提交作业,其格式如下: ./bin/spark-submit \ --class <main- ...

  9. javascript函数详解

    //函数的两种声明方式 //在同一个<script>标签中,函数的调用和声明位置可以没有先后的顺序,因为在同一个标签中,都是等加载到内存中,然后在运行 //但是如果是在两个script标枪 ...

  10. Python将mongodb导出的bson文件转为字典对象

    Python将mongodb导出的bson文件转为字典对象 安装bson包, sudo pip install bson 示例 # 解决编码问题 import sys reload(sys) sys. ...