# Hexadecimal -> Binary Art

Take a list of 2-digit hexadecimal numbers as input, and output the binary value, replacing each 1 with an 'X', and each 0 with a space.

For example

Input = FF, 81, 47, 99.

• FF = 11111111 in binary, so print XXXXXXXX
• 81 = 10000001 in binary, so print X X
• 47 = 01000111 in binary, so print  X XXX
• 99 = 10011001 in binary, so print X XX X

Full output:

XXXXXXXX
X      X
X   XXX
X  XX  X


Clarifications

• The hexadecimal numbers will always be 2-digits.
• There can be any number of hexadecimal numbers.
• You can choose to input in whatever format you want (separated by a space, comma, newline, etc.)
• The character to output for a 1 is X, and for 0 it is a  . This will not change.
• The outputs must be padded to length 8

Also, apparently I wasn't clear enough: the input is in Hexadecimal (Base 16) not denary (Base 10)

This is , so the shortest answer in bytes wins!

• Should the binary representations be left-padded with 0s to the length of the longest or always to length 8? Commented Sep 30, 2022 at 16:59
• @Shaggy - they must be padded to length 8, even if the biggest number is not 8 bits long. Commented Sep 30, 2022 at 17:02
• Please edit the question to clearly indicate the padding requirement (people are not supposed to read all comments), and maybe include a test case to address that Commented Sep 30, 2022 at 18:08
• For future challenges, consider relaxing the input and output requirements (such as allowing input in decimal or allowing a the answerer to choose the 1 character, not necessarily X). I don't think those restrictions make the challenge more interestin Commented Sep 30, 2022 at 18:10
• Is accepting a list of lists of integers from $[0,15]$ valid (i.e. a list of numbers in base sixteen) or should this be tagged string? Commented Sep 30, 2022 at 18:21

# Excel (ms365), 74, 72, 59, 58 bytes

-14 Byte thanks to @jdt

=SUBSTITUTE(SUBSTITUTE(HEX2BIN(+A1:A4,8),"0"," "),"1","X")


Original answer using BYROW() for 71 bytes:

=BYROW(A:A,LAMBDA(a,CONCAT(IF(-MID(HEX2BIN(a,8),ROW(1:8),1),"X"," "))))


• Welcome to Code Golf, and nice answer! Commented Sep 30, 2022 at 20:55
• I searched for alternatives for nested SUBSTITUTE functions and came upon your answer which did not really help =). It looks like you can save 1 byte: =BYROW(A:A,LAMBDA(a,CONCAT(IF(-MID(HEX2BIN(a,8),ROW(1:8),1),"X"," ")))).
– jdt
Commented Oct 2, 2022 at 13:16
• @jdt yeah I looked into that too but things get longer than the nested IF(). Good spot on the fact a negative integer will also trigger the TRUE parameter. Adjusted!
– JvdV
Commented Oct 2, 2022 at 14:10
• =SUBSTITUTE(SUBSTITUTE(HEX2BIN(0&A1:A4,8),"0"," "),"1","X")
– jdt
Commented Nov 3, 2022 at 23:52
• @jdt, you pulled of a way to make HEX2BIN() take an array. Sweet!
– JvdV
Commented Nov 4, 2022 at 7:52

# Ruby-p, 40 31 bytes

Takes input on stdin separated by newlines.

$_=("%08b "%$_.hex).tr"01"," X"


Attempt This Online!

# Python, 58 bytes

while 1:print(f"{int(input(),16):08b}".translate(" X"*99))


Attempt This Online!

Takes each hex code on a new line from input, prints to standard out. Terminates on error (is that allowed?)

# Python, 67 bytes

lambda n:"\n".join(f"{int(x,16):08b}".translate(" X"*99)for x in n)


Attempt This Online!

Takes input as a list of hex strings and returns a string with newlines separating lines.

• You're going to have to add '\n'.join somewhere. The output must be in the format of the example in the question. Commented Sep 30, 2022 at 17:13
• also this doesn't work correctly, you need bin(int(x,16))[2:].zfill(8), not bin(int(x,16)).zfill(8)[2:] Commented Sep 30, 2022 at 17:18
• You can save a few bytes with f'{int(x,16):>08b}' instead of bin(int(x,16))[2:].zfill(8) Commented Sep 30, 2022 at 17:31
• The > isn't necessary since we already know all the strings are of length 8. Commented Sep 30, 2022 at 20:17

# Japt-mR, 9 bytes

nG" X" ù8


Try it

nG" X" ù8    :Implicit map of input array
n            :Convert from base
G           :16
" X"       :To base " X"
ù8   :Left pad with spaces to length 8
:Implicit output joined with newlines


# Retina 0.8.2, 61 57 bytes

.
$& (?=..[89A-F]|.[4-7C-F]|[2367ABEF]) X +TdA-F Xo  Try it online! Explanation: .$&


Precede each digit with three spaces.

 (?=..[89A-F]|.[4-7C-F]|[2367ABEF])
X


Replace the spaces with Xs where appropriate.

+TdA-F Xo


Reduce the remaining digit modulo 2 and replace with space or X as appropriate.

• @JvdV From the OP: The hexadecimal numbers will always be 2-digits.
– Neil
Commented Oct 1, 2022 at 9:50
• Had to re-read and you are absolutely correct!
– JvdV
Commented Oct 1, 2022 at 9:53

$_=sprintf"%08b ",hex;y/01/ X/  Pretty much identical to Jordan's Ruby answer Try it online! • 24 bytes: Try it online! Commented Oct 3, 2022 at 4:22 # sed 4.2.2, -E178 141 bytes s/./&FEDCBA9876543210:/g s/(\w)\w*\1//g s/\w/ /g s/ +/&&&&/ s/ +/&&&&/ s/:// : s/^(.+)\1:/\1: / s/^ (.*)\1:/\1:X/ t s/:// :z s/^.{,7}$/ &/
tz


Takes newline-separated input

-35 thanks to DLosc

### Explanation

s/./&FEDCBA9876543210:/g  add hex digits to each input char
s/(\w)\w*\1//g            find index of input char in hex string
s/\w/ /g                  left is 2 strings which lengths corresponds to the input
s/ +/&&&&/
s/ +/&&&&/                multiply first strings' length by 16
s/://                     add the 2 strings, left is a unary number
:
s/^(.+)\1:/\1: /          convert to base 2, one bit at a time
s/^ (.*)\1:/\1:X/
t
s/://
:z
s/^.{,7}$/ &/ pad with spaces until length > 7 tz  • Nice work! I did some rearranging and got it down to 143 bytes. Commented Oct 1, 2022 at 16:13 • Even the naïve approach is only 175 bytes. – Neil Commented Oct 1, 2022 at 16:45 # JavaScript (ES6), 60 bytes -1 thanks to @MatthewJensen Expects a list of 2-character hexadecimal strings. a=>a.map(s=>(g=k=>k--?" X"['0x'+s>>k&1]+g(k):'')(8)).join   Try it online! ### Commented a => // a[] = input array a.map(s => // for each string s in a[]: ( g = k => // g is recursive function taking a counter k k-- ? // if k is not equal to 0 (decrement it afterwards): " X"[ // append either ' ' or 'X': '0x' + s // parse s as a hexadecimal string >> k // right-shift it by k position & 1 // and isolate the least significant bit ] // end of lookup + g(k) // append the result of a recursive call : // else: '' // stop the recursion )(8) // initial call to g with k = 8 ).join\n // end of map(); join with line-feeds  • Save one byte by starting recursion at 8: a=>a.map(s=>(g=k=>k--?' X'['0x'+s>>k&1]+g(k):'')(8)).join  Commented Oct 3, 2022 at 0:29 # Brainfuck, 442 bytes ++++++++++>>>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<<+>+>-]<----------------------------<++++++++++++++++++++++++++++>>,[------------------------------------------------[-[-[-[-[-[-[-[-[-[--------[-[-[-[-[-[<<<.>>>[-]>]<[<....>>]>]<[<...>.>]>]<[<..>.<.>>]>]<[<..>..>]>]<[<.>.<..>>]>]<[<.>.<.>.>]>]<[<.>..<.>>]>]<[<.>...>]>]<[.<...>>]>]<[.<..>.>]>]<[.<.>.<.>>]>]<[.<.>..>]>]<[..<..>>]>]<[..<.>.>]>]<[...<.>>]>]<[....>],]  Attempt This Online! The input can be separated by every character with a value bigger than 'F'. The working section looks like this: | '\n' | 'X' | ' ' | {input character} | 0 (used for stopping loops) | prepare the initial state ++++++++++ newline prepare space and X >>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ [<<+>+>-] < ---------------------------- space < ++++++++++++++++++++++++++++ X Go to start position and read char >>, [ subtract '0' ------------------------------------------------ [ if !0 -[ if !1 -[ if !2 -[ if !3 -[ if !4 -[ if !5 -[ if !6 -[ if !7 -[ if !8 -[ if !9 subtract difference between 'A' and '9' ------- -[ if !A -[ if !B -[ if !C -[ if !D -[ if !E -[ if !F print newline <<<.>>> clear input character [-]> ] <[ print 'F' <....>> ]> ] <[ print 'E' <...>.> ]> ] <[ print 'D' <..>.<.>> ]> ] <[ print 'C' <..>..> ]> ] <[ print 'B' <.>.<..>> ]> ] <[ print 'A' <.>.<.>.> ]> ] <[ print '9' <.>..<.>> ]> ] <[ print '8' <.>...> ]> ] <[ print '7' .<...>> ]> ] <[ print '6' .<..>.> ]> ] <[ print '5' .<.>.<.>> ]> ] <[ print '4' .<.>..> ]> ] <[ print '3' ..<..>> ]> ] <[ print '2' ..<.>.> ]> ] <[ print '1' ...<.>> ]> ] <[ print '0' ....> ] read next input , ]  # Vyxal, 10 8 bytes H‛ Xτ8↳⁋  Try it Online! -2 thanks to Steffan Port of Japt. • Your 6-byter suffers from the same issue with left-padding that my 5-byter did. Commented Sep 30, 2022 at 17:02 • @Shaggy oops, fixed. Commented Sep 30, 2022 at 17:09 # Husk, 3431 28 bytes mȯötm!"X "ḋ+256B16m€f□…"1F"w  Try it online! Takes input as a space-separated argument Husk is missing some useful functions such as pad and hex which makes this answer so long, or maybe I'm just bad. -3 DLosc -3 Razetime ### Explanation mȯötm!"X "ḋ+256B16m€f□…"1F"w w split on spaces mȯö map the following ultra composed penta-function m€f□…"1F" map input to indices the generated string "1-9A-F" B16 convert from digits in base 16 +256 add 256 to make the binary string 9 chars long ḋ convert to digits in base 2 m!"X " index into "X ", one-indexed modular t chop of first bit implicit output joined on newlines  • Commented Oct 1, 2022 at 5:01 • 26 bytes by prepending a 1 digit instead of adding 256... Commented Nov 4, 2022 at 13:04 • ...which would be 23 bytes by taking input as a list (as in the challenge description), rather than as a single string... Commented Nov 4, 2022 at 13:35 # C (clang), 80 74 bytes i;f(**b){for(i=8;*b;)putchar(i--?strtol(*b,0,16)&1<<i?88:32:(b++,i=8)+2);}  -3 bytes thanks to Arnauld!! Try it online! ### Alternative method proposed by Arnauld: # C (clang), 73 bytes i;f(**b){while(*b)putchar(++i%9?strtol(*b,0,16)&1<<8-i%9?88:32:!++b+10);}  Try it online! This will only work correctly for the first 477,218,588 lines. • 77 bytes by doing one more iteration for the linefeed. Commented Sep 30, 2022 at 18:48 • 73 bytes but not 100% valid (it's not infinitely reusable because i will eventually overflow and not be congruent to 0 modulo 9 anymore when the function terminates). Commented Sep 30, 2022 at 19:34 # Factor, 60 bytes [ [ hex> "%08b"sprintf "10""X "zip substitute print ] each ]  Try it online! • [ ... ] each Call [ ... ] on each hex string in the input sequence • hex> convert from hex to decimal • "%08b"sprintf format as a binary number string left-padded with spaces 8 wide • "10""X "zip create the following associative mapping: { { 49 88 } { 48 32 } } • substitute substitute characters in the binary string according to the mapping • print print to stdout with a newline # Charcoal, 13 bytes ＷＳ⟦◧⍘⍘↧ι¹⁶ X⁸  Attempt This Online! Link is to verbose version of code. Explanation: ＷＳ Loop over all lines of input ⟦ Output each result on its own line ι Current line ↧ Lowercased ⍘ ¹⁶ Converted from base 16 ⍘ X Converted to custom base  X ◧ ⁸ Left padded to length 8  # APL(Dyalog Unicode), 29 bytes SBCS ⍉' X'⌷⍨∘⊂2⊥⍣¯1(16⊥(⎕D,⎕A)∘⍳)¨  Try it on APLgolf! # Python, 89 bytes lambda n:[print(bin(int(i,16))[2:].zfill(8).replace("1","X").replace("0"," "))for i in n]  Function which takes in a list of hexadecimal strings. Try it online! # Python, 98 bytes [print(*('X'if int(b)else' 'for b in bin(int(a,16))[2:].zfill(8)),sep='')for a in input().split()]  Takes input itself, no header/footer code. Try it online! • a=lambda n:[print(bin(i)[2:].replace("1","X").replace("0"," "))for i in n].Works, but prints a list whose items are all None in the end. Commented Oct 1, 2022 at 3:03 • @py3programmer - thanks. I think bin(int(i,16)) was needed instead of just bin(i) since bin needs an integer as the parameter. Also, you need the .zfill(8) otherwise it won't print a leading space. Commented Oct 1, 2022 at 12:05 • Late comment, just pointing out on my answer: If you allow input to be taken as 0xFF instead of FF, you can shave off a byte by changing the bin(i,16) to bin(i,0) Commented Feb 18, 2023 at 17:47 # MATL, 10 bytes 1ZA8&B88*c  Try it online! ### How it works  % Implicit input: cell array of char vectors. 1ZA % Convert each char vector to number. Gives a numeric vector 8&B % Convert each number to 8-digit binary. Gives an 8-column binary matrix 88* % Multiply each element by 88 (ASCII code of 'X') c % Convert to char % Implicit display. char(0) is displayed as space  # K (ngn/k), 45 bytes {"\n"/|'8$|'" X"@+2\16/+"0123456789ABCDEF"?x}


Try it online!

This is way too long...

# Bash + coreutils + dc, 6858 51 bytes

Takes input as arguments.

-10 bytes thanks to Steffan
-7 bytes thanks to manatwork

for a;{
printf "%08s
" dc<<<2o16i$a?n|tr 01 \ X }  Try it online! • 58 bytes Commented Oct 3, 2022 at 2:48 • @Steffan Very clever. Thanks! Commented Oct 3, 2022 at 3:14 • Usually dc is shorter than bc. Try it online! Commented Oct 3, 2022 at 4:36 • If you let dc do the conversion from base 16, you can save another character: Try it online! Commented Oct 3, 2022 at 8:29 • @manatwork Thanks! Looks like I need to dig into dc. Commented Oct 3, 2022 at 13:03 # Pip-l, 17 bytes " X"@S*TDgFB16+E8  Takes the hex pairs as command-line arguments. Try It Online! ### Explanation " X"@S*TDgFB16+E8 g ;; List of command-line arguments FB16 ;; Converted (each) from base 16 + ;; Add (to each): E8 ;; 2 to the 8th power (256) TD ;; Convert (each) to binary as a list of digits S* ;; Get all but the first element of each " X"@ ;; Use those 0's and 1's to index into this string  The result is a depth-2 nested list of spaces and X's. The -l flag concatenates each sublist together and outputs it on a separate line. (For a flagless version, add P* to the beginning of the code and u to the end.) # Knight, 75 bytes ;=fB;=n 4W+=n-nT1O I%/-aI>60a 48 55^2n 2'X\'' \'W=pP;=aAp;Cf;=aA GpT1;CfO''  Try it online! Input each hexidecimal value on a separate line. Could be a bit shorter if it isn't required to output X's and spaces: ### Knight, 72 bytes ;=fB;=n 4W+=n-nT1O++''%/-aI>60a 48 55^2n 2'\'W=pP;=aAp;Cf;=aA GpT1;CfO''  Try it online! # PowerShell, 63 bytes %{[convert]::ToString("0x1$_",2)}|% S*g 1|% *ce 1 X|% *ce 0 ' '


Try it online!

Input comes from the pipeline.
Pretty straightforward; converts to binary, replaces 0 and 1.

run $F(["FF", "81", "47", "99"]);  Should output the expected result. ## Slightly more readable Both versions do exactly the same. fn($list) => {
&array_map(
$list, fn($line) => {
$translation = " X\n";$temp = call &format("%'08s2", &convert_base($line, 16, 2)); each$char in $temp { echo$translation[$char]; } } ); }  For some reason, JavaScript doesn't like the original order, when I untangle the code. # J, 26 bytes ' X'{~(8#2)#:[:".'16b'&,&>  Tacit function that expects a list of boxes using [0-9a-f]. Attempt This Online! ' X'{~(8#2)#:[:".'16b'&,&> '16b'&,&> : prepend '16b' to each input cell and unbox ". : Do, eval the list of strings [: : Cap, makes do and the prepend eval as f(g(x)) (8#2)#: : convert to binary and pad to length 8 ' X'{~ : use result to index into ' X'  # 05AB1E, 10 bytes Hb8j»T„X ‡  Try it online. Or alternatively: H„ XÅвJ8j»  Try it online. Explanation: H # Convert the values in the (implicit) input-list from hexadecimal to integers b # Then convert those base-10 integers to binary 8j # Pad leading spaces so all become length 8 » # Join the list with newline delimiter ‡ # Transliterate all T # 10 „X # to "X ", replacing all 1s with "X" and 0s with " " # (after which the result is output implicitly) H # Convert the values in the (implicit) input-list from hexadecimal to integers „ XÅв # Convert each integer to custom base-" X", which basically means to # base-length (2 in this case) and then indexing into the string J # Join the inner character-lists to strings 8j» # Same as above # (after which the result is output implicitly)  # C# 10 (.NET 6) and later, 184 bytes Doesn't work in TIO as it doesn't support .NET 6. foreach(var i in Console.ReadLine().Split(',')){var a=Convert.ToString(Convert.ToInt32(i,16),2).Replace("1","X").Replace("0"," ");a=new string(' ',8-a.Length)+a;Console.WriteLine(a);}  Asks for the hex numbers as input when started. Output: FF,81,47,99 XXXXXXXX X X X XXX X XX X  Ungolfed version: var input = Console.ReadLine(); // Ask for input foreach (var i in input.Split(',')) { // Split with a comma, and for each part: var hex = Convert.ToInt32(i, 16); // Convert it to an integer var bin = Convert.ToString(hex, 2); // Convert it to it's binary representation var art = bin.Replace("1", "X").Replace("0", " "); // Replace 1 with X, 0 with a space var padding = new string(' ', 8 - art.Length); // Repeat a space as much as needed for padding art = padding + art; // Append the padding to the start of the art string Console.WriteLine(art); // Write the final result }  ## Function version (155 bytes) Thanks to Seggan for the suggestion. void art(int[] n){foreach(var i in n){var a=Convert.ToString(i,2).Replace("1","X").Replace("0"," ");a=new string(' ',8-a.Length)+a;Console.WriteLine(a);}}  Try it online! Usage and output: art(new int[] { 0xFF, 0x81, 0x47, 0x99 }); /* gives this output: XXXXXXXX X X X XXX X XX X*/  • I'm sure this could be shortened by making this a function and taking in a list of numbers Commented Oct 2, 2022 at 20:23 • Welcome to Code Golf, and nice answer! Commented Oct 2, 2022 at 21:38 • 104 bytes – jdt Commented Oct 3, 2022 at 21:35 • note that you can do our var res in the function call - not that it affects anything here Commented Oct 3, 2022 at 22:02 • wait, is this even valid? question says you're supposed to take hexadecimal numbers (i.e. strings) as input Commented Oct 3, 2022 at 22:29 # Rust, 99 bytes |a|a.map(|s|format!("{:>8b}",u8::from_str_radix(&s,16).unwrap()).replace('0'," ").replace('1',"X"))  Try it online! Can be assigned a variable of type fn(std::vec::IntoIter<String>)->_ # sed-E, 131 121 bytes -10B thanks to @Neil s/./X&/g s/X([0-7])/ \1/g y/89ABCDEF/01234567/ s/[4-7]/X&/g s/[0-3]/ &/g s/[2367]/X&/g s/[0145]/ &/g y/01234567/ X X X X/  Attempt This Online! • – Neil Commented Oct 1, 2022 at 16:50 # Windows Batch, 145 bytes Length calculated by using Unix/LF as EOL, without an EOL at the end of the last line. :s @if %1.==. exit/b @set/an=0x%1&set b= :w @set/ar=n%%2&set/an/=2 @set b=%r%%b% @set b=%b:0=.%&if %b:~7,1%.==. goto w @echo.%b:1=X%&shift&goto s  Input as command line parameters. ### Ungolfed The @ suppresses the output of the command currently processed that would otherwise be echoed; "@echo off\n" would use 10 bytes, so suppressing lines individually is cheaper. :s &REM Start label @if %1.==. exit/b &REM Leave if no more parameter from the command line @set /a n=0x%1 &REM set n to the value of the first parameter (%1) as hexadecimal ("set /a" is an arithmetic operation) @(set b=) &REM Clear b (the output string) :w &REM Start of the loop to calculate the binary representation of n @set /a r=n%%2 &REM Set r to the remainder of n/2; % is the modulo operator, which must be doubled inside a batch script @set /a n/=2 &REM Divide n by 2 @set b=%r%%b% &REM Add the remainder to the output string @set b=%b:0= % &REM Replace every 0 in the output string with a space @if %b:~7,1%.==. goto w &REM If the eight character in the output string is not set yet, continue with the conversion @echo.%b:1=X% &REM Replace every 1 in the output string with an X, and write the string @shift &REM Shift the command line parameters to the left (former %2 is now %1, etc.) @goto s &REM Lather, rinse, repeat  D:\cmd>.\CGSE_252379.cmd FF 81 47 99 XXXXXXXX X X X XXX X XX X  # sh + coreutils, 82 72 bytes xxd -r -p|xxd -b|sed -E "s/^.{10}(.{53}).*/\1/g;s/ *$//g"|tr 01\  \ X\\n


Try it online!