在实际的数据分析中偶尔会遇到一种情况,需要在一组字符串中确定第一个出现的数字的位置。例如ABC123DEF这组字符串,第一个数字1出现在第4个位置上。通过获得第一个数字的位置后可以进而进行其他计算,例如提取其后的一组数字,或者获取数字前的字符串等。
在Excel中可以通过下面的公式获取示例中第一个数字出现的位置。
MIN(SEARCH({0,1,2,3,4,5,6,7,8,9},A2&"0123456789"))
如何获取的呢?实际上Excel的公式有三组函数:MIN,SEARCH以及CONCATENATE(在Excel中可以用&便捷的实现CONCATENATE函数作用)。
- CONCATENATE函数实现的是将两个文本字符串连接成一个文本字符串。在上面公式中,用CONCATENATE的目的是将所有要分析的字符串结尾处都补充上0123456789。之所以这么做是避免外层SEARCH函数有返回空的情况(例如字符串中没有任何数字),这样就不会出现将空结果作为参数传给最外层MIN函数,而导致抛出异常。
SEARCH的目的是在加工过后的字符串里面查找每个数字的位置。例如jio801在CONCATENATE函数处理过后就变为jio8010123456789一共17位字符串。SEARCH函数的目的就是从0开始挨个查找0-9这十个数每一个数最早在字符串中出现的位置。查找之后可以得出一组数列,如下图所示:
这里面0最早是在第5位出现的,1最早在第6位,2最早在第10位,一次search过后可以得到一个数组{5,6,10,11,12,13,14,15,4,17}MIN函数是为了在SEARCH函数获得的数组中取最小的那个数,这个最小的数就代表原始字符串中最先出现的数字所在的位置。例如在上图示例中SEARCH获取的数组最小的一个是4,对应的是原始字符串中位于第4位的数字8。
经过这三个函数的计算即可获得字符串中第一个数字出现的位置。这一思路在Power BI中同样适用,但是不能直接将Excel的公式搬到Power BI里面应用,原因是DAX语言中传入的参数不支持数组,必须是特定的一个数值。也就是说Excel中可以使用SEARCH{0,1,2,3,4,5,6,7,8,9}代表先SEARCH 0,之后再SEARCH 1,直到把大括号内的数据都search完得到一组数,但是在Power BI中就不行。DAX要求每次SEARCH函数只能传入一个要search的对象,然后获得一个结果。MIN函数也是类似的,只能比较两个参数之间的大小,不能多个比较。
因此要在Power BI中实现这个功能就需要使用下面过程。
- 先创建一列,将所有数据最后追加0-9这10个数字。
Extend = CONCATENATE([Simple],"0123456789")
- 使用多个MIN和SEARCH的嵌套公式来获取第一个数字出现的位置。这里面实际上是先search数字9,看看9出现的位置是否比10000小(10000是一个假设,假设的是所要提取的字符串追加10位后一共的位数不会超过10000),如果比10000小,再拿9的位数跟8比,看谁的位数小,小的那个再跟7比较,意思类推,获得最小的那个位数。
FirstNumberPosition = MIN(SEARCH("0",[Extend]),MIN(SEARCH("1",[Extend]),MIN(SEARCH("2",[Extend]),MIN(SEARCH("3",[Extend]),MIN(SEARCH("4",[Extend]),MIN(SEARCH("5",[Extend]),MIN(SEARCH("6",[Extend]),MIN(SEARCH("7",[Extend]),MIN(SEARCH("8",[Extend]),MIN(SEARCH("9",[Extend]),10000))))))))))
- 得到第一位数字出现的位置就可以用来截取一下左侧所有出现过的其他字符,公式也很简单:
LeftCharacters = LEFT([Simple],[FirstNumberPosition]-1)
同上一篇文章介绍的类似,由于DAX语言的特殊性,一些Excel中的方法无法直接用在Power BI中,需要进行改造后才可。此外一些数据整理也可以通过M语言在导入数据时进行,不必都依赖DAX语言来做。