Hex to ASCII and Back: A Practical Guide to Hex Encoding for Developers
Source: Dev.to
Hexadecimal Basics
Hexadecimal (base‑16) uses the symbols 0‑9 and A‑F.
Each hex digit represents 4 bits, so two hex digits represent one byte (8 bits).
| Decimal | Hex | Binary |
|---|---|---|
| 0 | 0 | 0000 |
| 1 | 1 | 0001 |
| … | … | … |
| 9 | 9 | 1001 |
| 10 | A | 1010 |
| 11 | B | 1011 |
| 12 | C | 1100 |
| 13 | D | 1101 |
| 14 | E | 1110 |
| 15 | F | 1111 |
Why base‑16? Because computers think in binary, and hex maps perfectly to binary — every 4 bits = 1 hex digit. It’s the most human‑readable way to represent binary data.
ASCII assigns a number (0‑127) to each character. Converting hex to ASCII means translating those numbers back to their character representations.
Converting Hex to ASCII and Back
Example conversion
| Hex | Decimal | ASCII |
|---|---|---|
| 48 | 72 | H |
| 65 | 101 | e |
| 6C | 108 | l |
| 6C | 108 | l |
| 6F | 111 | o |
Result: Hello 👋
Going the other direction is just as straightforward:
"Dev" → D(44) e(65) v(76) → 44 65 76
JavaScript
// Hex → ASCII
function hexToAscii(hex) {
return hex
.match(/.{1,2}/g)
.map(byte => String.fromCharCode(parseInt(byte, 16)))
.join('');
}
// ASCII → Hex
function asciiToHex(str) {
return Array.from(str)
.map(char => char.charCodeAt(0).toString(16).padStart(2, '0'))
.join(' ');
}
console.log(hexToAscii('48656C6C6F')); // "Hello"
console.log(asciiToHex('Hello')); // "48 65 6c 6c 6f"
Python
# Hex → ASCII
def hex_to_ascii(hex_string):
return bytes.fromhex(hex_string).decode('ascii')
# ASCII → Hex
def ascii_to_hex(text):
return ' '.join(f'{ord(c):02x}' for c in text)
print(hex_to_ascii('48656C6C6F')) # "Hello"
print(ascii_to_hex('Hello')) # "48 65 6c 6c 6f"
Bash (using xxd and od)
# Hex → ASCII
echo '48656C6C6F' | xxd -r -p
# Output: Hello
# ASCII → Hex (continuous)
echo -n 'Hello' | xxd -p
# Output: 48656c6c6f
# ASCII → Hex (pretty, space‑separated)
echo -n 'Hello' | od -A n -t x1
# Output: 48 65 6c 6c 6f
Practical Applications
-
Packet captures (Wireshark, tcpdump) show payloads in hex. Spotting ASCII text in a dump is a fundamental debugging skill:
0000 47 45 54 20 2f 61 70 69 GET /api 0008 2f 75 73 65 72 73 20 48 /users H 0010 54 54 50 2f 31 2e 31 TTP/1.1 -
Web colors are hex values:
color: #FF5733; /* R:255 G:87 B:51 */ background: #2D2D2D; /* Dark gray */ -
UTF‑8 encoding examples:
Character UTF‑8 hex é C3 A9 € E2 82 AC 🔥 F0 9F 94 A5 -
File signatures (magic numbers):
Format Hex signature PNG 89 50 4E 47 0D 0A 1A 0A JPEG FF D8 FF PDF 25 50 44 46 ( %PDF)GIF 47 49 46 38 ( GIF8) -
Memory addresses (e.g., from a crash dump):
Segfault at address 0x7FFE4B2A1000 Stack pointer: 0x00007FFEEFBFF5A0
Common Hex Formats
| Format | Example | Typical Use |
|---|---|---|
| Space‑separated | 48 65 6C 6C 6F | Hex dumps, debuggers |
| No separator | 48656C6C6F | URLs, hashes |
0x prefix | 0x48, 0x65 | C/C++, memory literals |
\x escape | \x48\x65 | Python, string literals |
% prefix | %48%65 | URL encoding |
ASCII vs. Extended/Unicode
| Encoding | Character | Hex bytes |
|---|---|---|
| ASCII | A | 41 |
| UTF‑8 | ñ | C3 B1 |
| UTF‑8 | 漢 | E6 BC A2 |
| UTF‑8 | 🚀 | F0 9F 9A 80 |
ASCII covers only 0‑127 (7 bits). Values 128‑255 belong to “extended ASCII” (varies by code page). Modern text uses Unicode, which is encoded in UTF‑8 as shown above.
Pro Tip
Lowercase letters start at 0x61, uppercase at 0x41. The difference is always 0x20 (32). Toggling case is therefore just flipping one bit.
Handy Tool
For quick, in‑browser conversion without sign‑ups or tracking, try hextoascii.co – paste hex, get ASCII (and vice versa).
Conclusion
Hex encoding is a fundamental skill that resurfaces in network debugging, binary analysis, color codes, and encoding issues. Once you internalize the conversion process, you’ll recognize patterns in hex dumps without thinking about it.
What’s the weirdest hex‑debugging situation you’ve encountered? Share it in the comments!