convert two chars at a time from a string to hex - string

I have the following piece of code which converts 1 char to a hex at a time. I want to convert two chars to a hex. ie 99ab should be treated as '99', 'ab' to be converted to its equivalent hex.
Current implementation is as follows
$final =~ s/(.)/sprintf("0x%X ",ord($1))/eg;
chop($final);
TIA

Your question doesn't make much sense. Hex is a string representation of a number. You can't convert a string to hex.
You can convert individual characters of a string to hex since characters are merely numbers, but that's clearly not what you want. (That's what your code does.)
I think you are trying to convert from from hex to chars.
6 chars "6a6b0a" ⇒ 3 chars "\x6a\x6b\x0a"
If so, you can use your choice of
$final =~ s/(..)/ chr(hex($1)) /seg;
or
$final = pack 'H*', $final;
The other possibility I can think of is that you want to unpack 16-bit integers.
6 chars "6a6b" ⇒ 13 chars "0x6136 0x6236" (LE byte order)
-or-
6 chars "6a6b" ⇒ 13 chars "0x3661 0x3662" (BE byte order)
If so, you can use
my #nums = unpack 'S<*', $packed; # For 16-bit ints, LE byte order
-or-
my #nums = unpack 'S>*', $packed; # For 16-bit ints, BE byte order
my $final = join ' ', map sprintf('0x%04X', $_), #nums;

Related

Bytes Object is Comma Separated Decimal Values (Python 3)

A machine I interface with at my work returns its frequency as a bytes object like this:
b'192,232,206,0'
This little-endian (I think that's right, I'm not great at remembering which is which) bytes object is supposed to translate to a hex bytes object \x00\xCE\xE8\xC0 which translates into decimal as 13560000. I have found that Python has int.from_bytes() which takes the hex bytes object and turns it to a nice integer, but when I apply that to my comma-separated bytes object where each bytes is a decimal value, I get an astronomically large number (3816634650710199623094969186609 to be exact). Can anyone help me out here?
It's a bit convoluted but you can convert the decimal numbers to hex strings and combine their byte values to assemble a number:
freq = b'192,232,206,0'
freq_bytes = b''
for decimal in freq.split(b','):
hex_str = hex(int(decimal))
if hex_str == '0x0':
hex_str += '0' # otherwise it won't convert
freq_bytes += bytes.fromhex(hex_str[2:]) # remove the 0x part
freq_int = int.from_bytes(freq_bytes, 'little')
gives 13560000

Binary Formatting Variables in TCL

I am trying to create a binary message to send over a socket, but I'm having trouble with the way TCL treats all variables as strings. I need to calculate the length of a string and know its value in binary.
set length [string length $message]
set binaryMessagePart [binary format s* { $length 0 }]
However, when I run this I get the error 'expected integer but got "$length"'. How do I get this to work and return the value for the integer 5 and not the char 5?
To calculate the length of a string, use string length. To calculate the length of a string in a particular encoding, convert the string to that encoding and use string length:
set enc "utf-8"; # Or whatever; you need to know this ahead of time for sanity's sake
set encoded [encoding convertto $enc $message]
set length [string length $encoded]
Note that with the encoded length, this will be in bytes whereas the length prior to encoding is in characters. For some messages and some encodings, the difference can be substantial.
To compose a binary message with the length and the body of the message (a fairly common binary format), use binary format like this:
# Assumes the length is big-endian; for little-endian, use i instead of I
set binPart [binary format "Ia*" $length $encoded]
What you were doing wrong was using s* which consumes a list of integers and produces a sequence of little-endian short integer binary values in the output string, and yet were feeding the list that was literally $length 0; and the string $length is not an integer as those don't start with $. We could have instead done [list $length 0] to produce the argument to s* and that would have worked, but that doesn't seem quite right for the context of the question.
In binary format, these are the common formats (there are many more):
a is for string data (mnemonically “ASCII”); this is binary string data, and you need to encode it first.
i and I are for 32-bit numbers (mnemonically “int” like in many programming languages, but especially C). Upper case is big-endian, lower case is little-endian.
s and S are for 16-bit numbers (mnemonically “short”).
c is for 8-bit numbers (mnemonically “char” from C).
w and W are for 64-bit numbers (mnemonically “wide integers”).
f and d are for IEEE binary floating point numbers (mnemonically “float” and “double” respectively, so 4 and 8 bytes).
All can be followed by an optional length, either a number or a *. For the number ones, instead of inserting a single number they insert a list of them (and so consume a list); numbers give fixed lengths, and * does “all the list”. For the string format indicator, a number uses a fixed number of bytes in the message (truncating or padding with zero bytes as necessary) and * does “all the string” (never truncating or padding).

What are length prefixed strings and what do they look like when encoded in 8-bit binary?

Here is the problem:
Pascal uses length prefixed strings, where the length of a string is encoded in 8-bit binary and stored
before the string. Give the bit string for “BYE!”, encoded in 8-bit ASCII, as it would be encoded in
Pascal.
I understand how the string "BYE!" would be encoded in 8-bit ASCII, but I don't understand how this is supposed to look with the length of the string encoded and stored before the string. I also know how to find the decimal equivalent values for each of the characters in the string, but I'm not sure if that is necessary to answer the question.
The string "BYE!" encoded in ASCII is: 'B' = 01000010, 'Y' = 01011001, 'E' = 01000101, '!' = 00100001.
The decimal equivalent for the string "BYE!" is: 'B' = 66, 'Y' = 89, 'E' = 69, '!' = 33.
The length of the string is 4 characters.
8 bit binary states that the number 4 is represented as 00000100
Therefore in pascal it should = 00000100 01000010 01011001 01000101 00100001
8-bit binary for the length of the string is different to 8-bit ascii it wants for the actual string.

How can I convert a character code to a string character in Lua?

How can I convert a character code to a string character in Lua?
E.g.
d = 48
-- this is what I want
str_d = "0"
You are looking for string.char:
string.char (···)
Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument.
Note that numerical codes are not necessarily portable across platforms.
For your example:
local d = 48
local str_d = string.char(d) -- str_d == "0"
For ASCII characters, you can use string.char.
For UTF-8 strings, you can use utf8.char(introduced in Lua 5.3) to get a character from its code point.
print(utf8.char(48)) -- 0
print(utf8.char(29790)) -- 瑞

transform string/char to uint8

Why does the expression:
test = cast(strtrim('3'), 'uint8')
produce 51?
This is also true for:
test = cast(strtrim('3'), 'int8')
Thanks.
Because 51 is the ASCII code for the character '3'.
If you want to transform the string to numeric 3, you should use
uint8(str2double('3'))
Note that str2double will ignore trailing spaces, so that strtrim isn't necessary.
EDIT
When a string is used in an numeric operation, Matlab automatically converts it to its ASCII value. For example
>> '1'+1
ans =
50
Because 51 is the ASCII value for the character '3'.
This is because '3' is seen as an ASCII character to matlab. By casting as a signed or unsigned integer (8 bits in this case) you are asking Matlab to convert an ASCII '3' to a decimal number. In this case the decimal number is 51. If you want to look at more conversions here is a basic document.

Resources