Search code examples
powerbipowerquerym

How to decodeURIComponent? (ex: "%2F%3F%26%3D" -> "/?&=")


How to convert this

qqqq%2Fwwww%3Feeee%26rrrr%3Dtttt

to this

qqqq/wwww?eeee&rrrr=tttt

?

Is there easy way to decode?


Solution

  • We have a URI encoding library function, Uri.EscapeDataString but we don't have an inverse to decode (which might have been an oversight). Feel free to suggest this feature at https://ideas.powerbi.com


    Writing your own is a little more complicated than text replace over "%" if there's any non-ASCII characters.

    Here's an M implementation that builds up the bytes then converts to text as UTF-8 binary:

    let
        InputData = Csv.Document("a=b
    =ab
    ab=
    abc☃def"),
    
        Uri.UnescapeDataString = (data as text) as text => let 
            ToList = Text.ToList(data),
            Accumulate = List.Accumulate(ToList, [ Bytes = {} ], (state, current) => 
                let
                    HexString = state[HexString]?,
                    NextHexString = HexString & current,
                    NextState = if HexString <> null
                      then if Text.Length(NextHexString) = 2
                          then [ Bytes = state[Bytes] & Binary.ToList(Binary.FromText(NextHexString, BinaryEncoding.Hex)) ]
                          else [ HexString = NextHexString, Bytes = state[Bytes] ]
                      else if current = "%"
                          then [ HexString = "", Bytes = state[Bytes] ]
                      else [ Bytes = state[Bytes] & { Character.ToNumber(current) } ]
                in
                    NextState),
            FromBinary = Text.FromBinary(Binary.FromList(Accumulate[Bytes]))
          in
            FromBinary,
    
        AddEscaped = Table.AddColumn(InputData, "Escaped", each Uri.EscapeDataString([Column1])),
    
        AddUnescaped = Table.AddColumn(AddEscaped, "Custom", each Uri.UnescapeDataString([Escaped]))
    in
        AddUnescaped
    

    (I'm kind of proud of the above, but I thought of an easier way, if you know that all the data is properly encoded.)

    You could concatenate the string into a URL and leverage the URL decoding feature of Uri.Parts like:

    Uri.UnescapeDataString = (data as text) as text => 
        Uri.Parts("http://whatever?a=" & data)[Query][a],