Android Question Adding a leading zero to hex string

Steve-h

Member
My application requires a 4 digit hex value sent as a string. I derive that from an int using :-
B4X:
private Sub intohex(intin As Int)As String
    Private output As String
    output = Bit.ToHexString(intin)
    Return(output)
End Sub

Problem is when the int value is below 4095 the returned string is only 3 digits, the first 0 is missing. I can detect when it is not there but can't figure a way of adding it to the string.
 

Brian Dean

Active Member
Licensed User
Longtime User
Thank you, Steve. In turn, I would like to say that yours is one of the most satisfying responses that I have ever received.
 
Upvote 1

udg

Expert
Licensed User
Longtime User
Another, very compact, option.
The advantage is that there's no loop, so immutable string output doesn't need to be recreated at each iteration.
B4X:
'Works for ints in the range 0-65535 (hex 0000-FFFF)
Private Sub intohex (intin As Int) As String
    Dim hexstr As String = Bit.ToHexString(intin)
    Return "0000".SubString2(0,4-hexstr.Length)&hexstr.ToUpperCase
End Sub

ps: remove final "ToUpperCase" if you don't need that.
pps: for the whole range of integers, modify like below
B4X:
Return "00000000".SubString2(0,8-hexstr.Length)&hexstr.ToUpperCase
 
Last edited:
Upvote 0

Steve-h

Member
Where that is plainly another excellent solution the problem for me is I don't understand what is happening and none of the documentation I have looked at seems to explain it either.

I really appreciate the rapid help this forum offers but where the solution is not completely obvious to a newcomer a simple explanation of what is happening in the code would add enormous value to the reply.

The problem here being code is often completely obvious to almost everyone but me.
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
other:
commonly used text padding on the left
B4X:
    Log(FillLeftWithChar("0", 2 - output.Length, output))
    Log(FillLeftWithChar("0", 4 - output.Length, output))
    Log(FillLeftWithChar("0", 8 - output.Length, output))

B4X:
Public Sub FillLeftWithChar(c As Char, n As Int, t As String) As String
    Dim sb As StringBuilder
    sb.Initialize
    For i = 1 To n
        sb.Append(c)
    Next
    Return sb.Append(t)
End Sub

1644866267963.png
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
It may be useful for some user.

B4X:
    Dim output As String = Bit.ToHexString(4095)
    
    Log(FillLTextWithChar("0", 1 - output.Length, output, "L")) 'Left filler
    Log(FillLTextWithChar("0", 4 - output.Length, output, "L")) 'Left filler
    Log(FillLTextWithChar("0", 8 - output.Length, output, "L")) 'Left filler

    Log("-------------------")

    Log(FillLTextWithChar("0", 1 - output.Length, output, "R")) 'Right Filler
    Log(FillLTextWithChar("0", 4 - output.Length, output, "R")) 'Right Filler
    Log(FillLTextWithChar("0", 8 - output.Length, output, "R")) 'Right Filler
    
    Log("-------------------")
    
    Log(FillLTextWithChar("0", 1 - output.Length, output, Null)) ' Only filler
    Log(FillLTextWithChar("0", 4 - output.Length, output, Null)) ' Only filler
    Log(FillLTextWithChar("0", 8 - output.Length, output, Null)) ' Only filler

B4X:
'p = (L)eft,  (R)igth,  Null or "" only filler
Public Sub FillLTextWithChar(c As Char, n As Int, t As String, p As String) As String
    Dim sb As StringBuilder
    sb.Initialize
    For i = 1 To n
        sb.Append(c)
    Next
    Select p.ToUpperCase
        Case "L"
            sb.Append(t)
        Case "R"
            sb.Insert(0, t)
    End Select
    Return sb
End Sub
1644871415308.png
 
Upvote 0

udg

Expert
Licensed User
Longtime User
the problem for me is I don't understand what is happening
Hi @Steve-h
please find below a step-by-step explanation of my code from post #7 above.

'Works for ints in the range 0-65535 (hex 0000-FFFF)
The comment specifies that the code works ok for the range indicated. If you try any valid integer outside that range (e.g. a negative or an higher positive) it will fail.
This is because the code is tailored to your use case "My application requires a 4 digit hex value", so it expects values in that range

Private Sub intohex (intin As Int) As String
This is the sub signature. Private means that the sub is private to the hosting module containing it. Other modules won't see it.

Dim hexstr As String = Bit.ToHexString(intin)
This is a short form for two distinct instructions:
B4X:
Dim hexstr as String                      'declares and creates a string variable
hextsr = Bit.ToHextString(intin)    ' calls function Bit.ToHextString passing it an integer and receiving back a string representing that int as an hex

Return "0000".SubString2(0,4-hexstr.Length)&hexstr.ToUpperCase
This is a very compact form for a few instructions
1. "0000" is equivalent to
Dim temp as String
temp = "0000"
2. SubString2(0,4-hexstr.Length)
Function SubString2 (applied to the preceding string) has the effect of extracting zero or more characters from the given string.
First parameters is the index of the first char to extract; second parameter is the index of the first char to ignore
Index count starts a zero (so the very first char in your string has index 0)
So, for example, "012345".SubString2(2,5) returns string "234" (without double-quotes)
3. Combining points 1 e 2 above we have "0000".SubString2(0,4-hexstr.Length)
which means "extract from string 0000 from zero to 4 chars depending on the length of string hexstr"
Now, from the initial comment, we know that hextstr length will be from 1 (for decimals 0 to 15) to 4 (from 4096 upwards)
So the final result is to retun as many 0s are needed in order to have a final string of 4 chars in all.
This explains why the code will fail for integers greater than 65535 or negative: they will produce an hex string longer than 4, so the second parameter wil be negative.
4. &hexstr
& is the concatenation operator. So it produces a new string that is the concatenation of the one preceding it with the one following it
In our case is the concatenation of the right number of zeroes produced by SubString2 and the hex string as returned by Bit.ToHextString(intin)
This is already your expected final result. Strings like 000a, 001f.. are retruned at this step.
5. ToUpperCase
This function converts to uppercase all the chars of the string it is applied to.
In our case, the string which chars are uppercased is "0000".SubString2(0,4-hexstr.Length)&hexstr
This will turn 000a to 000A, 001f to 001F and son on.
6 Return
This one is the last instruction in your sub. It returns to the calling code the object following it.
In our case, since we defined the Sub intohex as a "function" returning a string, it must return the string produced by the concatenation of actions performed from point 1 to point 5 above.

A final word.
In post #7 I highlighted that a benefit of this code is that it avoids the loop showed in post #3
Why it could be important (not necessarily in this context)?
Well, in Java (and so in B4X) strings are immutable objects. This means that when you modify a string behind the scene the JVM (Java Virtual machine) is allocating a new string on the heap with the new value (at least if that new value isn't already on the heap, but that's another story)
So the loop in post #3 causes the allocation of a new string for each 0 prefixed at each iteration
If your initial integer is 12 (hex C) the loop will produce the following strings
0C
00C
000C
then it will exit because it reached the 4 chars length is was looking for.
Note: don't be fooled by the concision of my code. Behind the scenes the JVM would certainly need to allocate temp strings so, in this case, the advantage could be simply apparent. :)



 
Upvote 0

Sandman

Expert
Licensed User
Yeah, I'll throw my solution into the ring also. Quite close to the one by @udg, but more compact.
B4X:
private Sub intohex(intin As Int)As String
    Dim hex As String = Bit.ToHexString(intin)
    Return "0000".SubString(hex.Length) & hex
End Sub
 
Upvote 1

udg

Expert
Licensed User
Longtime User
@Sandman : nice one šŸ‘
I'm so used to SubString2 that I overlooked SubString..

We could have a version based on a single line too, although it calls Bit.ToHexString twice
B4X:
private Sub intohex(intin As Int)As String
    Return "0000".SubString(Bit.ToHexString(intin).Length) & Bit.ToHexString(intin)
End Sub
 
Upvote 0

Sandman

Expert
Licensed User
We could have a version based on a single line too, although it calls Bit.ToHexString twice
Yeah, I saw that too. A little too code-golfy for me. :)

I actually aimed at this solution:
B4X:
private Sub intohex(intin As Int)As String
    Return ("0000" & Bit.ToHexString(intin)).Right(4)
End Sub

But then I remembered we don't have Right in B4X. Oh well. :)
 
Upvote 0

udg

Expert
Licensed User
Longtime User
I forgot to vote for your solution, sorry.
Now I did it so I can go back to cooking :)
 
Upvote 0
Top