人生没有彩排
每一天都是现场直播

自定义函数-文本函数

前言

这些自定义的文本函数弥补了DAX语言对文本处理的不足,提供了常用的文本处理函数,包括清洗、提取、转换和重组文本数据等。

使用方式

复制以下DAX查询代码,粘贴到PowerBI的查询视图中运行,即可导入文本函数库。

关于每个函数的具体语法与介绍,请参考左边菜单栏的具体函数页面。

DEFINE
/// 从字符串中返回第N个位置的分隔符后的文本,分隔符位置从1开始
FUNCTION XF.Str.AfterDelimiter = (str:string,delimiter:string,n:int64) =>
    IF(n>=1,
        VAR TransToPath = SUBSTITUTE(str,delimiter,"|")
        RETURN
        CONCATENATEX(
            ADDCOLUMNS(
                GENERATESERIES(n+1,PATHLENGTH(TransToPath)),
                "SubStr",PATHITEM(TransToPath,[Value])
            ),
            [SubStr],
            delimiter,
            [Value],ASC
        ),
        ERROR("分隔符位置应大于或等于1")
    )

/// 从字符串中返回指定索引位置的字符,索引位置从1开始
FUNCTION XF.Str.AtIndex = (str:string,index:int64) =>
    IF(index>=1,
        MID(str,index,1),
        ERROR("索引应大于或等于1")
    )

/// 从字符串中返回第N个位置的分隔符前的文本,分隔符位置从1开始
FUNCTION XF.Str.BeforeDelimiter = (str:string,delimiter:string,n:int64) =>
    IF(n>=1,
        VAR TransToPath = SUBSTITUTE(str,delimiter,"|")
        RETURN
        CONCATENATEX(
            ADDCOLUMNS(
                GENERATESERIES(1,MIN(n,PATHLENGTH(TransToPath))),
                "SubStr",PATHITEM(TransToPath,[Value])
            ),
            [SubStr],
            delimiter,
            [Value],ASC
        ),
        ERROR("分隔符位置应大于或等于1")
    )

/// 从字符串中返回指定分隔符中间的文本,可使用startIndex参数指定使用第几个起始分隔符,endIndex参数则指定使用第几个结束分隔符,只不过endIndex的起始位置是相对于startIndex后的
FUNCTION XF.Str.BetweenDelimiters = (str:string,startDelimiter:string,endDelimiter:string,startIndex:int64,endIndex:int64) =>
    IF(startIndex<1 || endIndex<1,
        ERROR("startIndex与endIndex参数应大于或等于1"),
        VAR StartDelimiterIndex = 
            DISTINCT(
                FILTER(
                    SELECTCOLUMNS(
                        GENERATESERIES(1,LEN(str)),
                        "Position",FIND(startDelimiter,str,[Value],BLANK())
                    ),
                    [Position]<>BLANK()
                )
            )
        VAR StartDelimiterIndex_AddRank = 
            ADDCOLUMNS(
                StartDelimiterIndex,
                "Rank",RANKX(StartDelimiterIndex,[Position],,1)
            )
        VAR StartIndex = COALESCE(MAXX(FILTER(StartDelimiterIndex_AddRank,[Rank]=startIndex),[Position]),LEN(str))
        VAR RightText = RIGHT(str,LEN(str)-StartIndex)
        VAR TransToPath = SUBSTITUTE(RightText,endDelimiter,"|")
        RETURN
        CONCATENATEX(
            ADDCOLUMNS(
                GENERATESERIES(1,MIN(endIndex,PATHLENGTH(TransToPath))),
                "SubStr",PATHITEM(TransToPath,[Value])
            ),
            [SubStr],
            endDelimiter,
            [Value],ASC
        )
    )

/// 从字符串中清除所有控制字符或零宽不可见字符
FUNCTION XF.Str.Clean = (str:string) =>
    CONCATENATEX(
        FILTER(
            GENERATE(
                GENERATESERIES(1,LEN(str)),
                VAR Char = MID(str,[Value],1)
                RETURN
                ROW("Char",Char,"Unicode",UNICODE(Char))
            ),
            VAR IsRemove =
                [Unicode] < 32
                || ([Unicode] >= 127 && [Unicode] <= 159) // 控制字符
                || [Unicode] IN {8203, 8204, 8205, 8232, 8233, 8288, 65279}  // 零宽 段分隔 BOM等
            RETURN
            NOT IsRemove
        ),
        [Char],
        "",
        [Value],ASC
    )

/// 判断指定字符串中是否包含另一个字符串,IsExact参数的值:1:区分大小写且不支持通配符,0:不区分大小写且可使用?与*通配符
FUNCTION XF.Str.IsContains = (str:string,findText:string,isExact:int64) =>
    IF(NOT isExact IN {0,1},
        ERROR("IsExact参数的可选取值仅为0或1"),
        SWITCH(
            isExact,
            1,CONTAINSSTRINGEXACT(str,findText),
            0,CONTAINSSTRING(str,findText)
        )
    )

/// 返回指定字符串末尾的N个字符
FUNCTION XF.Str.Ends = (str:string,n:int64) => RIGHT(str,n)

/// 判断字符串是否以指定的文本结尾,IsExact参数的值:1:区分大小写,0:不区分大小写
FUNCTION XF.Str.EndsWith = (str:string,endText:string,isExact:int64) =>
    IF(NOT isExact IN {0,1},
        ERROR("IsExact参数的可选取值仅为0或1"),
        VAR EndStr = RIGHT(str,LEN(endText))
        RETURN
        SWITCH(
            isExact,
            1,CONTAINSSTRINGEXACT(EndStr,endText),
            0,CONTAINSSTRING(EndStr,endText)
        )
    )

/// 将指定文本插入到字符串的指定索引位置,索引位置从1开始
FUNCTION XF.Str.InsertText = (str:string,index:int64,newText:string) =>
    IF(index>=1,
        REPLACE(str,index,0,newText),
        ERROR("索引应大于等于1")
    )

/// 检查值是否为文本
FUNCTION XF.Str.IsText = (val:anyval) => ISTEXT(val)

/// 返回指定字符串的字符数量,即文本长度
FUNCTION XF.Str.Length = (str:string) => LEN(str)

/// 将字符串中的所有字符改为小写
FUNCTION XF.Str.Lower = (str:string) => LOWER(str)

/// 若字符串长度小于指定长度,则在字符串的末尾填充指定字符直到达到指定长度,否则返回原字符串
FUNCTION XF.Str.PadEnd = (str:string,length:int64,char:string) =>
    IF(LEN(char)<>1,
        ERROR("填充字符参数必须为单个字符"),
        str&REPT(char,MAX(length-LEN(str),0))
    )

/// 若字符串长度小于指定长度,则在字符串的起始填充指定字符直到达到指定长度,否则返回原字符串
FUNCTION XF.Str.PadStart = (str:string,length:int64,char:string) =>
    IF(LEN(char)<>1,
        ERROR("填充字符参数必须为单个字符"),
        REPT(char,MAX(length-LEN(str),0))&str
    )

/// 返回字符串中的指定文本的出现位置,searchMode参数:0:返回第一次出现的位置索引,1:返回最后一次出现的位置索引,2:以表的形式返回所有出现的位置索引;索引位置从1开始
FUNCTION XF.Str.PositionOf = (str:string,findText:string,searchMode:int64) =>
    VAR AllPosition = 
        DISTINCT(
            FILTER(
                SELECTCOLUMNS(
                    GENERATESERIES(1,LEN(str)),
                    "Position",FIND(findText,Str,[Value],BLANK())
                ),
                [Position]<>BLANK()
            )
        )
    VAR MinPosition = MINX(AllPosition,[Position])
    VAR MaxPosition = MAXX(AllPosition,[Position])
    RETURN
    FILTER(
        AllPosition,
        SWITCH(
            searchMode,
            0,MinPosition=[Position],
            1,MaxPosition=[Position],
            2,TRUE(),
            ERROR("searchMode参数的可选取值仅为0或1")
        )
    )

/// 将字符串的每个单词的首字符转为大写,其他字符转为小写
FUNCTION XF.Str.Proper = (str:string) =>
    VAR lstr = LOWER(str)
    VAR CalKey = "AWASDQ~SCD!~@)SD"
    RETURN
    SUBSTITUTE(
        CONCATENATEX(
            GENERATE(
                GENERATESERIES(1,LEN(lstr)),
                VAR Cur = MID(lstr,[Value],1)
                VAR Pre = IF([Value]>1,MID(lstr,[Value]-1,1))
                VAR IsLetter_Cur = NOT CONTAINSSTRINGEXACT(UPPER(Cur),LOWER(Cur))
                VAR IsLetter_Pre = IF([Value]=1,FALSE(),NOT CONTAINSSTRINGEXACT(UPPER(Pre),LOWER(Pre)))
                VAR Out = IF(IsLetter_Cur && ([Value]=1 || NOT IsLetter_Pre),UPPER(Cur),Cur&CalKey)
                RETURN
                ROW("Out",Out,"Cur",Cur,"Pre",Pre,"is_Cur",IsLetter_Cur,"is_Pre",IsLetter_Pre)
            ),
            [Out],
            "",
            [Value],ASC
        ),
        CalKey,
        ""
    )

/// 从指定位置处开始,返回N个字符的子字符串,索引位置从1开始
FUNCTION XF.Str.Range = (str:string,startIndex:int64,n:int64) => MID(str,startIndex,n)

/// 从字符串中删除指定的所有字符,区分大小写;removeChars参数是一个字符串,该字符串内的每个字符就是要删除的指定字符
FUNCTION XF.Str.Remove = (str:string,removeChars:table) =>
    CONCATENATEX(
        FILTER(
            ADDCOLUMNS(
                GENERATESERIES(1,LEN(str)),
                "Char",MID(str,[Value],1)
            ),
            NOT CONTAINSSTRINGEXACT(removeChars,[Char])
        ),
        [Char],
        "",
        [Value],ASC
    )

/// 从指定位置处开始,删除N个字符,返回删除后的字符串,索引位置从1开始
FUNCTION XF.Str.RemoveRange = (str:string,startIndex:int64,n:int64) => REPLACE(str,startIndex,n,"")

/// 将指定的字符串重复N次
FUNCTION XF.Str.Repeat = (str:string,n:int64) => REPT(str,n)

/// 将字符串中的所有指定文本替换成新文本,可使用Position参数指定仅替换第几个位置的文本,索引位置从1开始,0代表替换所有
FUNCTION XF.Str.Replace = (str:string,old:string,new:string,position:int64) => 
    IF(position=0,
        SUBSTITUTE(str,old,new),
        SUBSTITUTE(str,old,new,position)
    )

/// 从指定位置处开始,将N个字符的子字符串替换成新文本,索引位置从1开始
FUNCTION XF.Str.ReplaceRange = (str:string,startIndex:int64,n:int64,newText:string) => REPLACE(str,startIndex,n,newText)

/// 将给定的字符串进行反转,返回反转后的字符串
FUNCTION XF.Str.Reverse = (str:string) =>
    CONCATENATEX(
        ADDCOLUMNS(
            GENERATESERIES(1,LEN(str)),
            "Char",MID(str,[Value],1)
        ),
        [Char],
        "",
        [Value],DESC
    )

/// 从字符串中删除未指定的所有字符,即只保留指定的字符,区分大小写;selectChars参数是一个字符串,该字符串内的每个字符就是要保留的指定字符
FUNCTION XF.Str.Selects = (str:string,selectChars:string) =>
    CONCATENATEX(
        FILTER(
            ADDCOLUMNS(
                GENERATESERIES(1,LEN(str)),
                "Char",MID(str,[Value],1)
            ),
            CONTAINSSTRINGEXACT(selectChars,[Char])
        ),
        [Char],
        "",
        [Value],ASC
    )

/// 按指定分隔符拆分字符串,返回单列的表
FUNCTION XF.Str.Split=(str:string,delimiter:string)=>
    VAR TransToPath = SUBSTITUTE(str,delimiter,"|")
    RETURN
    SELECTCOLUMNS(
        GENERATESERIES(1,PATHLENGTH(TransToPath)),
        "SubStr",PATHITEM(TransToPath,[Value])
    )

/// 将指定文本的每个字符作为分隔符来拆分字符串,返回单列的表
FUNCTION XF.Str.SplitAny=(str:string,delimiter:string)=>
    VAR CurText = str
    VAR DelimiterPositions = 
        SUMMARIZE(
            GENERATE(
                DISTINCT(
                    SELECTCOLUMNS(
                        GENERATESERIES(1,LEN(delimiter)),
                        "delimiterstr",MID(delimiter,[Value],1)
                    )
                ),
                DISTINCT(
                    FILTER(
                        SELECTCOLUMNS(
                            GENERATESERIES(1,LEN(CurText)),
                            "Position",FIND([delimiterstr],CurText,[Value],BLANK())
                        ),
                        [Position]<>BLANK()
                    )
                )
            ),
            [Position]
        )
    VAR SplitPositions =
        UNION(
            SELECTCOLUMNS({0},"Position",[Value]),
            DelimiterPositions,
            {LEN(CurText)+1}
        )
    VAR SplitPosition_AddIndex = ADDCOLUMNS(SplitPositions,"Index",RANKX(SplitPositions,[Position],,1))
    RETURN
    SELECTCOLUMNS(
        GENERATESERIES(1,COUNTROWS(SplitPositions)-1),
        "SubStr",
            VAR Start_ = SUMMARIZE(FILTER(SplitPosition_AddIndex,[Index]=[Value]),[Position])+1
            VAR End_ = SUMMARIZE(FILTER(SplitPosition_AddIndex,[Index]=[Value]+1),[Position])
            RETURN
            MID(CurText,Start_,End_-Start_)
    )

/// 返回指定字符串开始的N个字符
FUNCTION XF.Str.Starts = (str:string,n:int64) => LEFT(str,n)

/// 判断字符串是否以指定的文本开头,IsExact参数的值:1:区分大小写,0:不区分大小写
FUNCTION XF.Str.StartsWith = (str:string,startText:string,isExact:int64) =>
    IF(NOT isExact IN {0,1},
        ERROR("IsExact参数的可选取值仅为0或1"),
        VAR StartStr = LEFT(str,LEN(startText))
        RETURN
        SWITCH(
            isExact,
            1,CONTAINSSTRINGEXACT(StartStr,startText),
            0,CONTAINSSTRING(StartStr,startText)
        )
    )

/// 从字符串的起始与末尾两个方向删除指定的前导与尾随字符,区分大小写;TrimText参数是一个字符串,该字符串内的每个字符就是要删除的前导或尾随字符
FUNCTION XF.Str.Trim = (str:string,trimText:string) =>
    VAR CleanIndex = 
        FILTER(
            ADDCOLUMNS(
                GENERATESERIES(1,LEN(str)),
                "Char",MID(str,[Value],1),
                "IsTrim",CONTAINSSTRINGEXACT(trimText,MID(str,[Value],1))
            ),
            NOT [IsTrim]
        )
    VAR StartIndex = MINX(CleanIndex,[Value])
    VAR EndIndex = MAXX(CleanIndex,[Value])
    RETURN
    MID(str,StartIndex,EndIndex-StartIndex+1)

/// 从字符串的起始方向删除指定的前导字符,区分大小写;TrimText参数是一个字符串,该字符串内的每个字符就是要删除的前导字符
FUNCTION XF.Str.TrimStart = (str:string,trimText:string) =>
    VAR CleanIndex = 
        FILTER(
            ADDCOLUMNS(
                GENERATESERIES(1,LEN(str)),
                "Char",MID(str,[Value],1),
                "IsTrim",CONTAINSSTRINGEXACT(trimText,MID(str,[Value],1))
            ),
            NOT [IsTrim]
        )
    VAR StartIndex = MINX(CleanIndex,[Value])
    RETURN
    RIGHT(str,LEN(str)-StartIndex+1)

/// 从字符串的末尾方向删除指定的尾随字符,区分大小写;TrimText参数是一个字符串,该字符串内的每个字符就是要删除的尾随字符
FUNCTION XF.Str.TrimEnd = (str:string,trimText:string) =>
    VAR CleanIndex = 
        FILTER(
            ADDCOLUMNS(
                GENERATESERIES(1,LEN(str)),
                "Char",MID(str,[Value],1),
                "IsTrim",CONTAINSSTRINGEXACT(trimText,MID(str,[Value],1))
            ),
            NOT [IsTrim]
        )
    VAR EndIndex = MAXX(CleanIndex,[Value])
    RETURN
    LEFT(str,EndIndex)

/// 将字符串中的所有字符改为大写
FUNCTION XF.Str.Upper = (str:string) => UPPER(str)

其他

如果有任何问题或想法,欢迎在评论区提交你的需求与改进建议,一起完善该函数库!

赞(0) 打赏
版权声明:本文为夕枫的原创文章,著作权归作者所有,未经允许不得转载
文章名称:《PowerBI DAX自定义函数-文本函数》
文章链接:https://www.ximaple.com/posts/1295.html
订阅评论
提醒
guest
0 评论
最新
最久 最赞
内联反馈
查看所有评论

觉得文章有用的话就支持一下吧~

感谢您的打赏支持,我将持续输出有价值的内容!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册

Operation don't support