locked
How to convert numeric string to packed decimal (unsigned) RRS feed

  • Question

  • I have a numeric string like this: "123456" .  I need to have that data in packed decimal format (unsigned).  The result would look like this if it were in a byte array:  &H12 , &H34, &H56 .  No conversion from decimal to hex, just packing as shown. 
    Monday, January 18, 2016 10:17 PM

Answers

  • I have a numeric string like this: "123456" .  I need to have that data in packed decimal format (unsigned).  The result would look like this if it were in a byte array:  &H12 , &H34, &H56 .  No conversion from decimal to hex, just packing as shown. 

    AFAICT .Net doesn't support packed decimal directly.  All the COM import functions seem to rely on helper tools.

    Packed decimal can be created using code like this

            Dim Source As String = "123456"
            Dim S As Char() = Source.ToArray
    
            Dim R(2) As Byte
    
            For I As Integer = 0 To 2
                Dim Temp As Byte = (Val(S(I * 2)) And &HFF) << 4
                Temp = Temp Or (Val(S((I * 2) + 1)) And &HFF)
                R(I) = Temp
            Next

    • Proposed as answer by IronRazerz Tuesday, January 19, 2016 12:43 AM
    • Marked as answer by WestJefferson Tuesday, January 19, 2016 12:54 AM
    Tuesday, January 19, 2016 12:19 AM
  •  I am not really sure what you are asking or want as the outcome.  There are only 3 bytes in your example which is not enough to convert it to an unsigned integer or a Decimal value.  There would need to be 1 more byte to make an unsigned Integer which has 4 bytes and a Decimal value has 16 bytes.

     If you just want to split a string into the 3 numbers and add them to a byte array or a List(Of Byte) then perhaps this will do what you want.  You could pad the list with a zero to make up for the missing byte and then convert the bytes to a UInteger using the BitConverter class but,  there is not a method for getting a Decimal value from 16 bytes.

     If you need to use an Array of the bytes from the List,  you can simply use the ToArray method to do that like "Bts.ToArray".

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim s As String = "123456"
            Dim bts As New List(Of Byte)
    
            For i As Integer = 0 To s.Length - 1 Step 2
                bts.Add(CByte(s(i) & s(i + 1)))
            Next
    
            For Each b As Byte In bts
                RichTextBox1.AppendText(b.ToString & vbNewLine) 'just to show the 3 numbers from the list of bytes in a RichTextBox
            Next
        End Sub
     

     If this is not what you want then please give us a little more detail as to what you want as an outcome.  An actual Decimal value or whatever.

     If you need an actual Decimal type then you can look at the link below.  There is an example of how you can convert a Byte Array to a Decimal and a Decimal to a Byte Array.

    Convert System.Decimal to and from Byte Arrays (VB & C#)


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Monday, January 18, 2016 11:40 PM
    • Marked as answer by WestJefferson Tuesday, January 19, 2016 12:54 AM
    Monday, January 18, 2016 11:35 PM

All replies

  • May I suggest this GetBytes function described here: "How to: Convert Strings into an Array of Bytes in VB" found here: https://msdn.microsoft.com/en-us/library/ms172828.aspx

    The GetBytes method is described in details here: https://msdn.microsoft.com/en-us/library/ds4kkd55.aspx




    Cyrille Precetti
    Bonne Année! Happy New Year!


    Monday, January 18, 2016 10:42 PM
  •  I am not really sure what you are asking or want as the outcome.  There are only 3 bytes in your example which is not enough to convert it to an unsigned integer or a Decimal value.  There would need to be 1 more byte to make an unsigned Integer which has 4 bytes and a Decimal value has 16 bytes.

     If you just want to split a string into the 3 numbers and add them to a byte array or a List(Of Byte) then perhaps this will do what you want.  You could pad the list with a zero to make up for the missing byte and then convert the bytes to a UInteger using the BitConverter class but,  there is not a method for getting a Decimal value from 16 bytes.

     If you need to use an Array of the bytes from the List,  you can simply use the ToArray method to do that like "Bts.ToArray".

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim s As String = "123456"
            Dim bts As New List(Of Byte)
    
            For i As Integer = 0 To s.Length - 1 Step 2
                bts.Add(CByte(s(i) & s(i + 1)))
            Next
    
            For Each b As Byte In bts
                RichTextBox1.AppendText(b.ToString & vbNewLine) 'just to show the 3 numbers from the list of bytes in a RichTextBox
            Next
        End Sub
     

     If this is not what you want then please give us a little more detail as to what you want as an outcome.  An actual Decimal value or whatever.

     If you need an actual Decimal type then you can look at the link below.  There is an example of how you can convert a Byte Array to a Decimal and a Decimal to a Byte Array.

    Convert System.Decimal to and from Byte Arrays (VB & C#)


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Monday, January 18, 2016 11:40 PM
    • Marked as answer by WestJefferson Tuesday, January 19, 2016 12:54 AM
    Monday, January 18, 2016 11:35 PM
  • I thought I'd been pretty clear, but apparently not.  I have string of numbers, let's say "123456" which will be sent to a hardware device over a serial port.  The device requires that the numbers be in what we used to call "packed decimal" format.  So, the first two numbers, "12" will be represented as a single byte with the binary value of 12 or like this in binary - 0001 0010.  The second byte will have a binary value of 34 and the third byte will have a binary value of 56.  Forget the unsigned integer business.  A signed packed decimal number as I described above would appear in hex as - 123456F where F is the sign.  An unsigned packed decimal number would be 123456 and that's what I need. 

    I could do it all with bit shifts and associated manipulation, but there's probably a better way to do it. 

    Tuesday, January 19, 2016 12:09 AM
  • I have a numeric string like this: "123456" .  I need to have that data in packed decimal format (unsigned).  The result would look like this if it were in a byte array:  &H12 , &H34, &H56 .  No conversion from decimal to hex, just packing as shown. 

    AFAICT .Net doesn't support packed decimal directly.  All the COM import functions seem to rely on helper tools.

    Packed decimal can be created using code like this

            Dim Source As String = "123456"
            Dim S As Char() = Source.ToArray
    
            Dim R(2) As Byte
    
            For I As Integer = 0 To 2
                Dim Temp As Byte = (Val(S(I * 2)) And &HFF) << 4
                Temp = Temp Or (Val(S((I * 2) + 1)) And &HFF)
                R(I) = Temp
            Next

    • Proposed as answer by IronRazerz Tuesday, January 19, 2016 12:43 AM
    • Marked as answer by WestJefferson Tuesday, January 19, 2016 12:54 AM
    Tuesday, January 19, 2016 12:19 AM
  • Excellent!  I couldn't find any reference to packed decimal in the online documentation, so suspected it wasn't supported directly.  I didn't know how to accomplish the bit shifting, but now I see.  I had to modify the code just slightly to get the right result (see last line before Next):

            Dim Source As String = "123456"
            Dim S As Char() = Source.ToArray
    
            Dim R(2) As Byte
    
            For I As Integer = 0 To 2
                Dim Temp As Byte = (Val(S(I * 2)) And &HFF) << 4
                Temp = Temp Or (Val(S((I * 2) + 1)) And &HFF)
                R(I) = hex(Temp)
            Next

    The R array was thus: R(0) = 12, R(1) = 34 and R(2) = 56.   Many thanks for your help.

    • Marked as answer by WestJefferson Tuesday, January 19, 2016 12:38 AM
    • Unmarked as answer by WestJefferson Tuesday, January 19, 2016 12:54 AM
    Tuesday, January 19, 2016 12:38 AM
  • "Packed decimal can be created using code like this"

     Very interesting.  I knew you would know how to do this.   8)


    If you say it can`t be done then i`ll try it

    Tuesday, January 19, 2016 12:39 AM
  • @ WestJefferson,

     If Acamar answered your question,  you should mark his post as the answer,  not your post.


    If you say it can`t be done then i`ll try it

    Tuesday, January 19, 2016 12:43 AM
  • I had to modify the code just slightly to get the right result (see last line before Next)

    That change means the code no longer conforms to your original description, or to the usual meaning of packed decimal.  This is the original result:

    which agrees with what you originally posted. Packed decimal means that each digit is represented in one nibble.   Your change has converted the two nibbles to a byte value.

    Tuesday, January 19, 2016 1:11 AM
  • You are correct.  My brief test was faulty.  The code you provided stands as correct.
    Tuesday, January 19, 2016 2:39 AM
  • Another solution, and FWIW I am not a fan of Val().

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim buf() As Byte = StrToPckd("123456789")
        End Sub
    
        Public Function StrToPckd(StrToPck As String) As Byte()
            Dim buf As New List(Of Byte)
            'make source even, pad left or right
            If (StrToPck.Length And 1) = 1 Then
                StrToPck = StrToPck.Insert(0, "0") 'left
                'Source &= "0" 'right
            End If
    
            Dim pckd As Byte
            For x As Integer = 0 To StrToPck.Length - 1
                Dim b As Byte
                If Byte.TryParse(StrToPck(x), b) Then
                    If (x And 1) = 0 Then
                        pckd = b << 4
                    Else
                        pckd = pckd Or b
                        buf.Add(pckd)
                    End If
                Else
                    'todo error - not a number
                    Stop
                End If
            Next
            Return buf.ToArray
        End Function


    "Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.



    • Edited by dbasnett Tuesday, January 19, 2016 12:43 PM
    Tuesday, January 19, 2016 12:25 PM