Binary, Hex and Full-Width Characters: A Practical Guide
Two small text problems cause a surprising number of bugs: a number in the wrong base, and a full-width character hiding inside a string that looks perfectly normal. Both are easy to detect once you know what to look for.
- Bases that are powers of two convert by grouping bits - 4 binary digits make 1 hex digit and 3 make 1 octal digit, so no division is needed
- Each hex digit maps to exactly 4 bits, so 0xFF is 255 and 0x10 is 16 - missing or wrong prefixes change the value completely
- Full-width digits and letters are different code points from the ASCII ones, so a password typed in full-width mode can never match
- A full-width space is U+3000, not U+0020, and languages disagree about whether trim() removes it
- Every full-width letter or digit sits exactly 0xFEE0 above its half-width counterpart: full-width A is U+FF21, ASCII A is U+0041
- Both the base converter and the full-width converter run entirely in your browser, so nothing you type is uploaded
#When each number base shows up
Hex represents bytes, octal shows up in file permissions, and binary is the basis of bitwise work - each base has a fixed job rather than being interchangeable.
The value 255 written in all four bases, with where you actually meet it:
| Base | Written as | Where you see it |
|---|---|---|
| Binary (2) | 0b11111111 | Bitwise flags, permission masks |
| Octal (8) | 0o377 | Unix file modes, chmod 755 |
| Decimal (10) | 255 | Application fields, everyday numbers |
| Hexadecimal (16) | 0xFF | Bytes, memory addresses, colour values, hashes |
Type a value into the Base Converter and pick its current base; all four representations update live, including negatives, fractions and integers larger than 2^53.
The prefixes are what people get wrong. 0x means hex, 0b means binary and 0o means octal, so 10 and 0x10 differ by a factor of six.
#How to convert between bases
Bases that are powers of two convert by grouping bits, with no division required. This is the fastest way to convert by hand, and the one most often done backwards.
#Binary and hex: four bits per digit
One hex digit equals exactly 4 binary digits, so group from the right in fours and read each group:
binary 1011 1111 0000 1101
grouped B F 0 D
result 0xBF0DGoing the other way is easier still: expand each hex character into a fixed 4-bit group, padding the leftmost group with zeros if needed.
#Binary and octal: three bits per digit
One octal digit equals 3 binary digits, so the group width is 3 rather than 4:
binary 111 101 010
grouped 7 5 2
result 0o752Always group from the right. Grouping from the left breaks whenever the bit count is not a multiple of 3 or 4 - 1011 split as 101|1 gives a wrong answer.
#Fractions need their own method
Fractional parts use repeated multiplication, which runs in the opposite direction from the division used for the integer part. Convert the two halves separately, then join them.
0.625 * 2 = 1.25 take 1
0.25 * 2 = 0.5 take 0
0.5 * 2 = 1.0 take 1
result: 0.101A decimal like 0.1 has no finite binary representation, so the conversion always loses a little precision. That is the same reason 0.1 + 0.2 does not equal 0.3 in most languages.
#Why full-width characters break software
Full-width and half-width characters are different characters, and software does not treat them as equivalent - which is why a password that looks right can still be wrong.
- Full-width digit
1is U+FF11; ASCII1is U+0031 - Full-width letter
Ais U+FF21; ASCIIAis U+0041 - Full-width space
is U+3000; ASCII space is U+0020 - Full-width underscore
_is U+FF3F; ASCII_is U+005F
They may look only slightly wider on screen, but string comparison, hashing and unique database indexes all see two different values. The user sees "my password is correct"; the program sees "no match".
Chinese IMEs in punctuation mode also convert digits, letters and underscores to full-width. This is the single most common cause of failed logins, and no validator reports a format error - you only see "incorrect username or password", which sends you looking in the wrong place.
#Finding the full-width character in your text
Check the character and byte counts first, then compare code points - doing it the other way round wastes a lot of time.
| Symptom | Cause | What to use |
|---|---|---|
| Login fails but the password looks identical | A digit or letter is full-width | Full/Half Width |
| Form rejects input as containing illegal characters | A full-width space U+3000 | Text Counter for the byte count |
JSON contains escapes such as \uff11 | A full-width character was serialised | Unicode Converter |
| Duplicate rows still insert despite a unique index | Full-width and half-width treated as two records | Full/Half Width |
A reliable order of work:
- Copy the failing string and compare its character and byte counts against what you expect
- Compare it against a string you know is correct to isolate the odd character
- Run it through Full/Half Width and compare again
- Update the stored value or password only after the fix is confirmed - do not relax the validation instead
The full-width converter leaves CJK characters and Chinese punctuation alone and only touches letters, digits, punctuation and spaces, so converting a whole Chinese paragraph is safe.
#Other uses for full-width conversion
Beyond fixing logins, full-width conversion is a data-cleaning step: normalise text before storing, comparing or searching it.
The three situations where it matters most:
- Text copied out of Excel, PDFs or chat apps often has full-width digits and brackets
- Chinese typography rules want half-width digits and letters but full-width sentence punctuation
- Search backends need normalised input, or "ABC" and "ABC" return different result sets
Watch the length change: one full-width character takes 3 bytes in UTF-8, and its half-width form takes 1. If the target column has a length limit, re-check it after converting.
The converter only changes code points. It does not convert between simplified and traditional Chinese, and it does not change letter case.
#Which tool for which job
| What you need | Tool | Notes |
|---|---|---|
| Convert across base 2, 8, 10 and 16 | Base Converter | Enter one value, all four bases update |
| Turn full-width letters and digits into half-width | Full/Half Width | CJK characters and punctuation stay as they are |
| Count characters versus bytes | Text Counter | A mismatch reveals hidden characters |
Escape Chinese as \uXXXX | Unicode Converter | Useful when debugging encoding |
| Turn a byte stream into readable text | Base64 Encode/Decode | Base conversion handles numbers, not bytes |
| Verify a file has not changed | SHA Hash | The classic use of a hex digest |
#Frequently asked questions
#My password is definitely correct, but login still fails. Why?
Suspect full-width characters first. An IME in punctuation mode produces full-width letters, digits and underscores, which are different code points and therefore never match the stored hash. Paste the password into Full/Half Width, convert it to half-width and try again - that confirms the theory in seconds.
#Is 0x10 ten or sixteen?
Sixteen. The 0x prefix means hexadecimal, so 0x10 is 1x16 + 0 = 16. Likewise 0b10 is binary 2 and 0o10 is octal 8. The same digits mean completely different values depending on the prefix, which is the most common mistake in base conversion.
#What are binary, octal and hexadecimal actually used for?
Hex packs binary data into a readable form - two characters per byte - which is why hashes and memory addresses use it. Octal survives mainly in Unix file modes such as chmod 755 and in some escape syntaxes. Binary is the underlying representation used for bitwise operations and flags. Decimal exists for humans; the machine only ever sees binary.
#Why is a full-width space so hard to track down?
It is U+3000, not U+0020, and on screen it just looks like slightly more space, so it survives copy and paste unnoticed. Worse, languages disagree about it: JavaScript's trim() and Python's strip() remove it, while Java's String.trim() only strips U+0020 and below. The same data behaves differently per language. Text Counter shows the byte count, which settles it.
#Does the base converter handle fractions and very large integers?
Yes. Integer parts are computed with BigInt, so values above 2^53 keep full precision. Fractional parts follow IEEE 754 binary floating point, so decimals such as 0.1 that have no finite binary form will lose a little precision. Negative values keep their sign. When precision is critical, pass the number as a decimal string instead.
Tools used in this guide
Convert between base 2, 8, 10, 16, 36 and 64 in real time
Open tool →Full/Half WidthConvert full-width characters to half-width and vice versa
Open tool →Base64 Encode/DecodeEncode and decode Base64 text with UTF-8 support; use the image tool for files
Open tool →Unicode ConverterConvert Chinese to/from \uXXXX escape sequences
Open tool →Word CounterCount words, characters, lines, paragraphs and bytes as you type. Free, no si…
Open tool →SHA HashSHA-1 / SHA-256 / SHA-512 hash generator for text or files
Open tool →