To convert hexadecimal to text, split the hex into two-digit pairs, turn each pair into a decimal number from 0 to 255, then look up that number as an ASCII character. For example 48 65 6C 6C 6F becomes Hello. You can do it instantly with the hex encoder / decoder, but the three steps below let you do it by hand and understand exactly what each byte means.
TL;DR
- Hexadecimal is base 16: digits
0-9thenA-Ffor the values 10-15. - Each pair of hex digits is one byte = one number from 0 to 255 = (usually) one character.
- Three steps: pair up the digits → hex to decimal → decimal to ASCII.
48 65 6C 6C 6F 20 57 6F 72 6C 64= Hello World.- Plain ASCII is one byte per character; accented letters and emoji are UTF-8 and use two to four bytes (
C3 A9is é). - Clean the input first: remove spaces, colons and
0xprefixes, then make sure only0-9 A-Fremain and the count is even.
What Is Hexadecimal?
Hexadecimal (“hex”) is a base-16 number system. Where decimal uses ten digits (0-9), hex uses sixteen: 0 1 2 3 4 5 6 7 8 9 A B C D E F, where A=10, B=11, up to F=15. It is popular in computing because one hex digit represents exactly four bits, so a single byte (eight bits) is always written as exactly two hex digits — from 00 (0) to FF (255). That tidy two-digit-per-byte mapping is what makes hex a compact way to write the raw bytes behind text, colors, or memory.
Step 1 — Split the Hex Into Byte Pairs
Text stored as hex is a run of bytes, and each byte is two hex digits. So the first move is always to group the string two digits at a time. Spaces (or separators like :) are just there for readability — remove them first, then re-pair:
48656C6C6F → 48 · 65 · 6C · 6C · 6F
If your string has an odd number of digits after removing separators, something is wrong — a byte is missing a digit. Some sources also prefix hex with 0x (as in 0x48); strip the 0x before pairing.
Step 2 — Convert Each Pair From Hex to Decimal
A two-digit hex byte has a “sixteens” place and a “ones” place, exactly like decimal has tens and ones. Multiply the first digit by 16 and add the second digit:
| Hex | Calculation | Decimal |
|---|---|---|
| 48 | 4×16 + 8 | 72 |
| 65 | 6×16 + 5 | 101 |
| 6C | 6×16 + 12 | 108 |
| 6F | 6×16 + 15 | 111 |
| 20 | 2×16 + 0 | 32 |
Remember that the letter digits are values: A=10, B=11, C=12, D=13, E=14, F=15. So in 6C, the C is 12, giving 6×16 + 12 = 108.
Step 3 — Map Each Number to Its ASCII Character
Now read each decimal number as a character using ASCII, the standard that assigns numbers 0-127 to letters, digits, and symbols (32 is a space, 65 is A, 97 is a). Our five bytes become:
72 → H, 101 → e, 108 → l, 108 → l, 111 → o = Hello.
Extend the same run and 48 65 6C 6C 6F 20 57 6F 72 6C 64 decodes to Hello World — note 20 is the space between the two words.
Worked Example: Decode a Longer Hex String
Here is a second string, an example made up for this guide, decoded one byte at a time. Input: 48 65 78 20 74 6F 20 74 65 78 74. Each row is “first digit × 16 + second digit”, with A-F counted as 10-15.
| Hex | Calculation | Decimal | Character |
|---|---|---|---|
| 48 | 4×16 + 8 | 72 | H |
| 65 | 6×16 + 5 | 101 | e |
| 78 | 7×16 + 8 | 120 | x |
| 20 | 2×16 + 0 | 32 | (space) |
| 74 | 7×16 + 4 | 116 | t |
| 6F | 6×16 + 15 | 111 | o |
| 20 | 2×16 + 0 | 32 | (space) |
| 74 | 7×16 + 4 | 116 | t |
| 65 | 6×16 + 5 | 101 | e |
| 78 | 7×16 + 8 | 120 | x |
| 74 | 7×16 + 4 | 116 | t |
Read the last column top to bottom: Hex to text. Eleven pairs, eleven bytes, eleven characters. If you want to check your own arithmetic, the decimal ASCII converter shows the decimal side of the same table.
Printable ASCII Hex Table (20-7E)
To read the grid, take the row label for the first hex digit and the column label for the second. Row 4_, column 8 is 48, which is H; row 6_, column C is 6C, which is l. SP is the space character (20); 7F (DEL) is a control code, not a printable character. The grid was generated from the character codes by script, not typed in.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2_ | SP | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / |
| 3_ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
| 4_ | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
| 5_ | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
| 6_ | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
| 7_ | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | DEL |
Two patterns fall out of this: uppercase letters start at 41 (A) and lowercase at 61 (a), so any lowercase letter is exactly 20 (32) higher than its uppercase form. Digits 0-9 sit at 30-39, which is why hex dumps of numbers look so regular.
The Reverse: Text to Hex
Going the other way, take each character’s ASCII number and write it as two hex digits. Hi! is H=72, i=105, !=33, which in hex is 48 69 21. To convert a decimal number to hex by hand, divide by 16: the quotient is the first digit and the remainder is the second (105 ÷ 16 = 6 remainder 9, so 69).
Input Formats and Error Checks
Before pairing digits, clean the input the same way every time: remove spaces, :, - and commas, remove each 0x or \x prefix, then check that every remaining character is 0-9 or A-F and that the count is even. All seven inputs below are examples; the first five decode to the same five bytes.
| Input | After clean-up | Result |
|---|---|---|
| 48 65 6C 6C 6F | 48656C6C6F | Hello |
| 48:65:6C:6C:6F | 48656C6C6F | Hello |
| 0x48 0x65 0x6C 0x6C 0x6F | 48656C6C6F | Hello |
| \x48\x65\x6C\x6C\x6F | 48656C6C6F | Hello |
| 48656c6c6f | 48656c6c6f | Hello |
| 48656C6C6 | 48656C6C6 | Error: 9 digits cannot form whole bytes |
| 48 65 6C 6C 6G | 48656C6C6G | Error: “G” is not a hex digit |
Be careful with tools that skip the checks. The site’s hex encoder decodes by deleting every character that is not a hex digit and pairing what is left. That is fine for spaces and colons, but 0x48 0x65 0x6C 0x6C 0x6F loses its x and keeps the 0, so the pairs shift and the output is control characters and wrong letters instead of Hello; and the odd input 48656C6C6 decodes to “Hell” plus a stray control character (byte 06) with no error. Remove prefixes yourself first, or use the Unicode converter, which understands 0x prefixes.
Formats and Pitfalls
- Case doesn’t matter for the value:
6cand6Care the same byte (108). Uppercase is just a convention. - Separators are cosmetic:
48 65,4865, and48:65all decode the same — strip spaces and colons before pairing. - The
0xprefix marks a value as hex in code (0x48); it is not part of the byte, so remove it. - Non-ASCII text is UTF-8: characters beyond plain ASCII take more than one byte. The letter
éis the two bytesC3 A9, the euro sign isE2 82 AC, and emoji are four bytes. Decode byte-by-byte as ASCII and you get garbled symbols; the next section shows the arithmetic. - Odd digit count = error: valid hex text always has an even number of digits once separators are removed.
Multi-Byte UTF-8: é, €, and Emoji by Hand
ASCII only covers 0-127. Everything else is stored as UTF-8, where the first byte says how many bytes the character takes: 0xxxxxxx is one byte, 110xxxxx starts a two-byte character, 1110xxxx a three-byte one, and 11110xxx a four-byte one. Every following byte starts with 10 and carries six more bits. Strip those marker bits, join what is left, and you get the Unicode code point.
| Character | Code point | UTF-8 hex | Bytes in binary |
|---|---|---|---|
| é | U+00E9 | C3 A9 | 11000011 10101001 |
| € | U+20AC | E2 82 AC | 11100010 10000010 10101100 |
| 😀 | U+1F600 | F0 9F 98 80 | 11110000 10011111 10011000 10000000 |
Decoding E2 82 AC by hand: the bytes are 11100010 10000010 10101100. Drop the marker bits (1110, 10, 10) and join 0010 + 000010 + 101100 = 0010 0000 1010 1100 = 20AC = 8364, the euro sign U+20AC. The same method turns C3 A9 into 00011 + 101001 = E9 = 233 (é), and F0 9F 98 80 into 000 + 011111 + 011000 + 000000 = 1F600 = 128512 (the grinning-face emoji).
What goes wrong if you read these bytes one at a time as ASCII or Latin-1 (computed, not guessed):
| Hex | Intended | One character per byte gives |
|---|---|---|
| C3 A9 | é | two characters, é |
| E2 82 AC | € | three characters: â, an invisible control character (U+0082), and ¬ |
| F0 9F 98 80 | 😀 | four characters: ð followed by three invisible control characters (U+009F, U+0098, U+0080) |
The reverse failure also exists: bytes that are not valid UTF-8 have no correct reading. A lone C3 (a two-byte lead with nothing after it), a lone 80 (a continuation byte with no lead), and C3 28 (a lead followed by a non-continuation byte) are all rejected by a strict UTF-8 decoder; a lenient decoder replaces them with the “�” replacement character.
This site has two hex tools and they differ on exactly this point. The hex encoder / decoder works one byte per character, so it is right for plain ASCII but turns C3 A9 into the two characters above, and it encodes € as its UTF-16 code unit 20ac rather than E2 82 AC. For UTF-8 hex use the Unicode converter in its “UTF-8 Bytes” mode, which uses the browser’s own UTF-8 encoder and decoder.
Test Vectors You Can Recompute
These eight strings are examples chosen for this guide. Each hex value was decoded two independent ways, with Python’s bytes.fromhex(...).decode('utf-8') and with the JavaScript TextDecoder that this site’s tests use, and both agreed on every row. To check one yourself, paste it into either snippet below.
| Hex | UTF-8 text | Bytes |
|---|---|---|
| 48 65 6C 6C 6F | Hello | 5 |
| 48 65 78 20 74 6F 20 74 65 78 74 | Hex to text | 11 |
| 31 30 2F 31 30 | 10/10 | 5 |
| 61 3D 31 | a=1 | 3 |
| 43 61 66 C3 A9 | Café | 5 |
| C3 A9 | é | 2 |
| E2 82 AC | € | 3 |
| F0 9F 98 80 | 😀 | 4 |
python3 -c "print(bytes.fromhex('43 61 66 C3 A9').decode('utf-8'))"
node -e "console.log(new TextDecoder().decode(Uint8Array.from('43 61 66 C3 A9'.split(' '),h=>parseInt(h,16))))"
Both print Café: five bytes for four characters, because the accented letter takes two bytes. That mismatch is why the byte count and the character count of a decoded string can differ.
FAQ
How do I convert hex to text?
Split the hex into two-digit pairs, convert each pair to a decimal number (first digit × 16 + second digit), then read that number as an ASCII character. For instance 48 65 6C 6C 6F is 72, 101, 108, 108, 111 = Hello.
What does each pair of hex digits mean?
Each pair is one byte, a value from 0 to 255. In plain ASCII text, one byte is one character; in UTF-8, accented letters and emoji span two to four bytes.
Why does hex use letters A to F?
Hex is base 16, so it needs sixteen digit symbols. After 0-9 it borrows A-F to represent the values 10 through 15, which keeps every byte to exactly two characters (00-FF).
Does uppercase or lowercase hex matter?
No. 6C and 6c represent the same value (108). Case and separators like spaces or colons are only for readability.
Why did my hex decode to gibberish?
Usually the text was UTF-8 rather than plain ASCII, so multi-byte characters were split, or separators/an 0x prefix threw off the pairing. Remove prefixes and separators, check for an even digit count, and use a UTF-8-aware decoder for non-English text.
How do I convert hex to text when it contains accented letters or emoji?
Decode the bytes as UTF-8, not one byte per character. C3 A9 is é, E2 82 AC is € and F0 9F 98 80 is a four-byte emoji. Use a UTF-8 decoder such as the Unicode converter’s “UTF-8 Bytes” mode, or Python’s bytes.fromhex(...).decode('utf-8').
Do I have to remove spaces and 0x before decoding hex?
Spaces, colons and commas are only separators, and 0x or \x only marks the next two digits as hex, so none of them is data. Remove them before pairing. A tool that just deletes non-hex characters will leave the 0 of each 0x behind and shift every pair.
Why does my hex string have an odd number of digits?
Every byte needs two digits, so valid hex has an even count. An odd count usually means a leading zero was dropped (5 instead of 05), a digit was lost when copying, or the string includes an extra character. Fix the source rather than padding blindly, because a pad on the wrong end changes every byte.
Is hex a cipher or encryption?
No. Hex is an encoding: a different way to write the same bytes, with no key and no secret. Anyone can reverse it in seconds, as the steps above show. It makes bytes readable and copyable; it does not hide them.
Convert and Check It Yourself
Hex isn’t a code to crack — it is just base 16 wearing a disguise. Once you see each pair as “a number from 0 to 255,” converting hex to text is only two small lookups per byte.
Convert plain ASCII instantly with the hex encoder / decoder, use the Unicode converter for UTF-8 bytes, switch between bases with the binary ↔ hex converter, inspect character codes in the ASCII converter, compare sizes in Base64 vs hex, or read the companion guide on converting binary to text. Browse every encoder in the tools list.