EXCEL中从一个字符串里提取连续数字引发的思考(二)
从一个字符串中提取连续数字的函数
=LOOKUP(9E+307,--MID(A1,MIN(FIND({0,1,2,3,4,5,6,7,8,9},A1&"0123456789")),RO W(INDIRECT("$1:$"&LEN(A1)))))引发的思考(二)
依然假设A1=“总人口7895432个”,A列的内容都是这种形式的,你的任务就是把其中的数字单独提取出来放到B列。
以B1单元格为例:
在上一篇中,使用LOOKUP的框架中会使用到MID,思路还显得很曲折和原始,那么可否就直接以MID为框架来提取数字呢?答案是肯定的,思路也比较简洁,尽管使用起来看似复杂,像下面这样写。
=1*MID(A1,MATCH(TRUE,ISNUMBER(1*MID(A1,ROW(INDIRECT("$A1:$"&"A"&LEN (A1))),1)),0),COUNT(1*MID(A1,ROW(INDIRECT("$A1:$"&"A"&LEN(A1))),1)))
接上篇,讲解之前有必要先来认识下ROW和COLUMN函数,这是取行号和列号的函数,那么其参数必须是引用(单元格、行或列)。
比如ROW(C1)=1,COLUMN(C1)=3。
将参数里的单一单元格变成单元格矩阵的话,就会返回一个数组,比如ROW(A1:A5)={1;2;3;4;5},按Ctrl+shift+enter结束输入就会看到公式被{}括起来了,说明是一个数组,而单元格里只显示数组的第一个。
常见的懒人写法ROW(1:100)只写了行号,简直是一种赤裸裸的浪费计算资源的写法,从A 到Z有26列,然后AA到AZ、BA到BZ......这样排列组合下来得有26^26种组合了,计算了多少次啊!简直瞎搞嘛,取个行号而已,大可以写成ROW(A1:A100)或ROW(B1:B100)等等简单明了,按需计算100次而已。
所以,在此篇中,ROW(INDIRECT ("$1:$"&LEN(A1))) 升级成
ROW(INDIRECT("$A1:$"&"A"&LEN(A1)))以减轻计算机负荷。
说到正题,用ROW按字符串长度生成一个序列,为什么要用
ROW(INDIRECT("$A1:$"&"A"&LEN(A1))) ,而不能想当然的直接写ROW($1:$LEN(A1))?因为ROW函数的参数必须是引用!静态的写法ROW(1:100)或ROW(A1:A100)是引用,加了LEN函数就变成动态的了,需要间接引用函数Indirect、Offset或Index来帮忙。
一般常见的是组合Indirect的写法,用法就像C语言里的指针一样。
在静态写法INDIRECT(A1:A3)下,假设A1单元格的内容是B3,A2单元格内容是"哇哈哈",A3为空,而B3单元格内容是"我靠",则INDIRECT(A1:A3)={"我靠";#REF!;#REF!}。
如果加入LEN 函数变成动态的,而且以单元格("A1":"A3")的形式作参数,不会返回单元格的引用值,而是直接返回单元格内容,INDIRECT("$A1:$"&"A"&LEN(A2))={"B3";"哇哈哈";0}。
因为Row和Column可以引用自身,所以Row、Column套任何函数以后,仍然可以引用自身,但Indirect却不行,所以如果直接写Indirect("1:10"),那么公式不能写在1至10
行里的任意单元格里,否则报循环。
这里Indirect肯定是循环了,不过不影响,外套了ROW 之后,还是能返回正确结果的。
接下来就来讲下此MID框架的思路,挨个分析A1单元格的字符,第一次碰到是数字的就记下其位置,MID就从这个位置开始提取,提取的位数则用COUNT来计算。
首先使用ROW(INDIRECT("$A1:$"&"A"&LEN(A1)))按字符个数生成数组
{1;2;3;4;5;6;7;8;9;10;11};
然后使用MID(A1,ROW的结果,1)把A1单元格的字符串从第一位开始到最后一位,一个字符一个字符的取出来,形成字符数组{“总”;”人”;”口”;”7”;”8”;”9”;”5”;”4”;”3”;”2”;"个"};
再*1转换成数字{#VALUE!;#VALUE!; #VALUE!;”7”;”8”;”9”;”5”;”4”;”3”;”2”; #VALUE!};
使用ISNUMBER判断1*MID的结果是否为数字,返回值为TRUE或者FALSE;
然后用MATCH(TRUE, ISNUMBER数组,0)返回第一个数字7所在位置4,MID就从这里开始提取数字;
至于MID的第三个参数则用COUNT(1*MID)计算数字个数;
整体来看,就是MID(A1,MATCH第一个数字位置,COUNT数字个数)提取出数值,然后*1转换成数字完结。
有数组一定要用CTRL+SHIFT+ENTER结束输入。
思路很简单,只是看起来写得复杂而已,最后的结果就是:
=1*MID(A1,MATCH(TRUE,ISNUMBER(1*MID(A1,ROW(INDIRECT("$A1:$"&"A"&LEN (A1))),1)),0),COUNT(1*MID(A1,ROW(INDIRECT("$A1:$"&"A"&LEN(A1))),1)))。