Visualización de números en palabras

Un usuario Pregunto ✅

edzigmann

Hola,

Estoy viendo la forma de mostrar números como palabras usando DAX.

Tengo una medida DAX de suma básica y quiero que la pantalla se muestre en palabras, por lo que el ejemplo sería si el total es 100, entonces me gustaría que muestre «cien» si el total suma 10,5, entonces quiero que se muestre «once».

¿Hay alguna manera de mostrar números de la medida de esa manera?

lbendlin

En respuesta a lbendlin

Aquí hay una versión más concisa que también se puede extender fácilmente a más trillizos de dígitos, ya que la tabla de búsqueda será la misma para cada uno de los trillizos.

Spelt2 = 
var l = {("1","one","eleven","ten"),("2","two","twelve","twenty"),("3","three","thirteen","thirty"),
("4","four","fourteen","fourty"),("5","five","fifteen","fifty"),("6","six","sixteen","sixty"),
("7","seven","seventeen","seventy"),("8","eight","eighteen","eighty"),("9","nine","nineteen","ninety")}
var t = "0" & format(ParameterNumber[ParameterNumber Value],"https://community.powerbi.com/t5/DAX-Commands-and-Tips/Displaying-Numbers-in-Words/td-p/#")
var s = right(t,1)
var d = left(right(t,2),1)
var h = left(right(t,3),1)
var sd = if(d="1",concatenatex(filter(l,[Value1]=s),[Value3]),concatenatex(filter(l,[Value1]=s),[Value2]))
var dd = if(d>"1" || d & s = "10",concatenatex(filter(l,[Value1]=d),[Value4]) & " ")
var hd = if(h>"0",concatenatex(filter(l,[Value1]=h),[Value2]) & " hundred ")
return hd & dd & sd 

Aquí está la versión de hasta seis dígitos:

Spelt2 = 
var l = {("1","one","eleven","ten"),("2","two","twelve","twenty"),("3","three","thirteen","thirty"),
("4","four","fourteen","fourty"),("5","five","fifteen","fifty"),("6","six","sixteen","sixty"),
("7","seven","seventeen","seventy"),("8","eight","eighteen","eighty"),("9","nine","nineteen","ninety")}
var t = "0" & format(ParameterNumber[ParameterNumber Value],"https://community.powerbi.com/t5/DAX-Commands-and-Tips/Displaying-Numbers-in-Words/td-p/#")
var s = right(t,1)
var d = left(right(t,2),1)
var h = left(right(t,3),1)
var ss = if(d="1",concatenatex(filter(l,[Value1]=s),[Value3]),concatenatex(filter(l,[Value1]=s),[Value2]))
var dd = if(d>"1" || d & s = "10",concatenatex(filter(l,[Value1]=d),[Value4]) & " ")
var hd = if(h>"0",concatenatex(filter(l,[Value1]=h),[Value2]) & " hundred ")
var s2 = left(right(t,4),1)
var d2 = left(right(t,5),1)
var h2 = left(right(t,6),1)
var ss2 = if(d2="1",concatenatex(filter(l,[Value1]=s2),[Value3]),concatenatex(filter(l,[Value1]=s2),[Value2])) 
var dd2 = if(d2>"1" || d2 & s2 = "10",concatenatex(filter(l,[Value1]=d2),[Value4]) & " ")
var hd2 = if(h2>"0",concatenatex(filter(l,[Value1]=h2),[Value2]) & " hundred ")
return if(ss2>"",hd2 & dd2 & ss2 & " thousand ") & hd & dd & ss 

En acción:

lbendlin_0-1596932916335.png

Anónimo

@edzigmann

Esto es lo que traté de implementar esto usando una medida.

Actualmente esto maneja hasta 9999.

EX = 
//Currently Handles Upto 9999


//Number to be converted into words. Replace this with SELECTEDVALUE or as desired.
VAR Number = SELECTEDVALUE(T[Value])//115

VAR NumberToText = "" & Number

VAR NoOfDigits =
    LEN ( NumberToText )

VAR Ones =
    SELECTCOLUMNS (
        GENERATESERIES ( 0, 9, 1 ),
        "Ones Digit", [Value],
        "Ones Digit in Words", SWITCH (
            [Value],
            1, "One",
            2, "Two",
            3, "Three",
            4, "Four",
            5, "Five",
            6, "Six",
            7, "Seven",
            8, "Eight",
            9, "Nine"
        )
    )
VAR OneTens =
    SELECTCOLUMNS (
        GENERATESERIES ( 1, 9, 1 ),
        "One Tens Digit", [Value],
        "One Tens Words", SWITCH (
            [Value],
            1, "Eleven",
            2, "Twelve",
            3, "Thirteen",
            4, "Fourteen",
            5, "Fifteen",
            6, "Sixteen",
            7, "Seventeen",
            8, "Eighteen",
            9, "Nineteen"
        )
    )
VAR Tens =
    SELECTCOLUMNS (
        GENERATESERIES ( 1, 9, 1 ),
        "Tens Place", [Value],
        "Tens Words", SWITCH (
            [Value],
            1, "Ten",
            2, "Twenty",
            3, "Thirty",
            4, "Fourty",
            5, "Fifty",
            6, "Sixty",
            7, "Seventy",
            8, "Eighty",
            9, "Ninety"
        )
    )
VAR PlaceValue =
    SELECTCOLUMNS (
        GENERATESERIES ( 3, 6, 1 ),
        "Place", [Value],
        "Place Value", SWITCH ( [Value], 3, "Hundred", 4, "Thousand")
    )


VAR X =
    SELECTCOLUMNS (
        GENERATESERIES ( 1, NoOfDigits, 1 ),
        "Index", [Value],
        "Dec",
        VAR N =
            INT ( Number / INT ( 1 & REPT ( "0", [Value] - 1 ) ) )
        RETURN
            MOD ( N, 10 )
    )
VAR numberMod100 = MOD(Number, 100)
VAR Y =
    ADDCOLUMNS (
        X,
        "Text", SWITCH (
            TRUE (),
            [Index] = 1, SWITCH (
                TRUE (),
                numberMod100 > 10
                    && numberMod100 < 20, MAXX ( FILTER ( OneTens, [One Tens Digit] = [Dec] ), [One Tens Words] ),    
                MAXX ( FILTER ( Ones, [Ones Digit] = [Dec] ), [Ones Digit in Words] )
            ),
            [Index] = 2, SWITCH (
                TRUE (),
                numberMod100 > 10
                    && numberMod100 < 20, "",
                MAXX ( FILTER ( Tens, [Tens Place] = [Dec] ), [Tens Words] )
            ),
            // Handles for 1-9 and beyond index 2
            IF (
                [Dec] = 0,
                "",
                // get the Word representation of current Digit
                MAXX ( FILTER ( Ones, [Ones Digit] = [Dec] ), [Ones Digit in Words] )
                // Concatenate the current digit with its place value.
                 & " " & MAXX ( FILTER ( PlaceValue, [Place] = [Index] ), [Place Value] )
            )
        )
    )
RETURN
    CONCATENATEX(Y, [Text], " ", [Index], DESC)

Esto se puede ampliar para manejar todos los números naturales con unas pocas líneas más de DAX.

Espero que entiendas la idea.

Espero que @lbendlin pueda ayudar en esto. No sé si hay una mejor manera que esta.

Gracias

lbendlin

En respuesta a Anónimo

Para inglés simplificado, solo necesita resolver el último grupo de tres dígitos, en un patrón 1-2. Cualquier otro lugar de dígitos más grandes es solo una repetición, con «mil», «millones», etc.

Al menos esa es mi teoría…

lbendlin

En respuesta a lbendlin


Aquí está mi versión para los últimos tres dígitos. «Número de parámetro[ParameterNumber value]» es la medida que desea convertir. No se devuelve nada para cero.

Spelt = 
var t = "000" & format(ParameterNumber[ParameterNumber Value],"https://community.powerbi.com/t5/DAX-Commands-and-Tips/Displaying-Numbers-in-Words/td-p/#")
var s = right(t,1)
var ss = switch(s,"1","one","2","two","3","three","4","four","5","five","6","six","7","seven","8","eight","9","nine","")
var sd = right(t,2)
var sds = switch(sd,"01","one","02","two","03","three","04","four","05","five","06","six","07","seven","08","eight","09","nine","10","ten"
                 ,"11","eleven","12","twelve","13","thirteen","14","fourteen","15","fifteen","16","sixteen","17","seventeen"
                 ,"18","eighteen","19","nineteen","")
var t1 = left(t,len
var d = right(t1,1)
var ds = switch(d,"2","twen","3","thir","4","four","5","fif","6","six","7","seven","8","eigh","9","nine","")
var dd = switch(d,"0","","1","",ds & "ty ")
var t2 = left(t1,len(t1)-1)
var h = right(t2,1)
var hs = switch(h,"1","one","2","two","3","three","4","four","5","five","6","six","7","seven","8","eight","9","nine","")
var hd = switch(h,"0","",hs & " hundred ")
return hd & dd & if(d<"2",sds,ss) 

lbendlin

En respuesta a lbendlin

Aquí hay una versión más concisa que también se puede extender fácilmente a más trillizos de dígitos, ya que la tabla de búsqueda será la misma para cada uno de los trillizos.

Spelt2 = 
var l = {("1","one","eleven","ten"),("2","two","twelve","twenty"),("3","three","thirteen","thirty"),
("4","four","fourteen","fourty"),("5","five","fifteen","fifty"),("6","six","sixteen","sixty"),
("7","seven","seventeen","seventy"),("8","eight","eighteen","eighty"),("9","nine","nineteen","ninety")}
var t = "0" & format(ParameterNumber[ParameterNumber Value],"https://community.powerbi.com/t5/DAX-Commands-and-Tips/Displaying-Numbers-in-Words/td-p/#")
var s = right(t,1)
var d = left(right(t,2),1)
var h = left(right(t,3),1)
var sd = if(d="1",concatenatex(filter(l,[Value1]=s),[Value3]),concatenatex(filter(l,[Value1]=s),[Value2]))
var dd = if(d>"1" || d & s = "10",concatenatex(filter(l,[Value1]=d),[Value4]) & " ")
var hd = if(h>"0",concatenatex(filter(l,[Value1]=h),[Value2]) & " hundred ")
return hd & dd & sd 

Aquí está la versión de hasta seis dígitos:

Spelt2 = 
var l = {("1","one","eleven","ten"),("2","two","twelve","twenty"),("3","three","thirteen","thirty"),
("4","four","fourteen","fourty"),("5","five","fifteen","fifty"),("6","six","sixteen","sixty"),
("7","seven","seventeen","seventy"),("8","eight","eighteen","eighty"),("9","nine","nineteen","ninety")}
var t = "0" & format(ParameterNumber[ParameterNumber Value],"https://community.powerbi.com/t5/DAX-Commands-and-Tips/Displaying-Numbers-in-Words/td-p/#")
var s = right(t,1)
var d = left(right(t,2),1)
var h = left(right(t,3),1)
var ss = if(d="1",concatenatex(filter(l,[Value1]=s),[Value3]),concatenatex(filter(l,[Value1]=s),[Value2]))
var dd = if(d>"1" || d & s = "10",concatenatex(filter(l,[Value1]=d),[Value4]) & " ")
var hd = if(h>"0",concatenatex(filter(l,[Value1]=h),[Value2]) & " hundred ")
var s2 = left(right(t,4),1)
var d2 = left(right(t,5),1)
var h2 = left(right(t,6),1)
var ss2 = if(d2="1",concatenatex(filter(l,[Value1]=s2),[Value3]),concatenatex(filter(l,[Value1]=s2),[Value2])) 
var dd2 = if(d2>"1" || d2 & s2 = "10",concatenatex(filter(l,[Value1]=d2),[Value4]) & " ")
var hd2 = if(h2>"0",concatenatex(filter(l,[Value1]=h2),[Value2]) & " hundred ")
return if(ss2>"",hd2 & dd2 & ss2 & " thousand ") & hd & dd & ss 

En acción:

lbendlin_0-1596932916335.png

edzigmann

En respuesta a lbendlin

Esto realmente funcionó. Me tomó un tiempo entender lo que está haciendo la medida, pero en realidad me gusta, ya que también puedo usarla en otros escenarios.

Muchas gracias por la ayuda. Personalmente, me pareció un buen desafío.

lbendlin

En respuesta a lbendlin

Además de ser un buen desafío de solución, esto también saca a relucir uno de los lados más feos de DAX. A diferencia de Power Query M (que tiene la capacidad de declarar funciones incluso si no se usan posteriormente), DAX no admite funciones «por si acaso» o la aplicación de una medida a partes de un punto de datos.

Digamos que tiene un número de siete dígitos en su tabla y desea deletrearlo. Idealmente, convertiría el número en texto, dividiría el texto en grupos de tres y pasaría los trillizos a través de la medida de ortografía, recibiendo el texto completo de vuelta.

Las medidas DAX no parecen funcionar de esa manera, siempre necesitan la completo valor de un existente elemento a trabajar. Tampoco admiten llamadas recursivas (que yo sepa).

No estoy seguro de si los grupos de cálculo pueden ser una posible respuesta a esto, pero lo dudo mucho. @marcorusso

En respuesta a lbendlin

Podría crear un grupo de cálculo Conversiones con un elemento de cálculo ToWords:

VAR OriginalValue = SELECTEDMEASURE () 
RETURN <your code to convert OriginalValue in words>

Luego aplica esa conversión a cualquier medida usando CALCULAR:

CALCULATE (
    [your existing measure],
    Conversions[Name] = "ToWords"
)

No me gusta, pero debería funcionar.

La realidad es que necesitamos funciones personalizadas en DAX.

lbendlin

¿En qué idiomas y qué dialectos? ¿Esperas «dos mil ciento cuarenta y cinco» o «veintiuno cuarenta y cinco»? etc

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *