Art stolen from What size is the digit?

7-segment digits can be represented in ASCII using _| characters. Here are the digits 0-9:

 _     _  _       _   _  _   _   _
| | |  _| _| |_| |_  |_   | |_| |_|
|_| | |_  _|   |  _| |_|  | |_|  _|


Your job is to parse the art into normal numbers.

### Notes on numbers

• Each digit has a different width.
• 1 has a width of 1
• 3 and 7 are 2 wide
• 245689 and 0 are all 3 wide

Also between each digit is one char of padding. Here is the full char set:

 // <-- should be one space, but SE formatting messed it up
|
|
-------------
_
_|
|_
-------------
_
_|
_|
-------------

|_|
|
-------------
_
|_
_|
-------------
_
|_
|_|
-------------
_
|
|
-------------
_
|_|
|_|
-------------
_
|_|
_|
-------------
_
| |
|_|


### Input

Input can be either from the console or as a string arg to a function.

### Output

Output is either put to the console or is returned from the function.

## Examples:

  _  _   _
|  |  | |_
|  |  | |_|
1776

_   _     _
_| | | | |_
|_  |_| | |_|
2016

_       _
| |_| |_| |_
|  _|   |  _|
1945

_   _   _   _   _   _
| | | | | | | | | | | | |
| |_| |_| |_| |_| |_| |_|
1000000

_     _  _       _   _  _   _   _
| | |  _| _| |_| |_  |_   | |_| |_|
|_| | |_  _|   |  _| |_|  | |_|  _|
0123456789


This is code-golf so shortest byte count wins!

• Related – J Atkin Feb 13 '16 at 20:48
• I am interested in learning about the best algorithms to solve this kind of problem, and I'm having difficulty learning from the answers here (they're good, just very concise). Is there a place you can refer me to see more lengthy explanations, preferably with pictures? – user51366 Feb 17 '16 at 1:51
• Well, The way mine works is fairly simple. It transposes the list and loops over it. It then splits on empty lines. Each number is checked against a fingerprint table for each number. The others work a bit like mine, except instead of a fingerprint table they basically have a hash table they use. – J Atkin Feb 17 '16 at 1:57
• Is there a more general name for this type of problem in computer science? – user51366 Feb 17 '16 at 2:10
• I have no idea ;) – J Atkin Feb 17 '16 at 2:57

## Pyth, 33 30 bytes

sm@."/9Àøw"%%Csd409hTcC.z*3d


Here's the idea: Once we transpose the input, and split into digits, we can sort of hash the individual digit strings and assign them to their values.

sm@."/9Àøw"%%Csd409hTcC.z*3d     Implicit: z=input
C.z        Transpose input.
c   *3d     Split that on "   ", a space between digits.
m@."/9Àøw"%%Csd409hT            Map the following lambda d over that. d is a digit string.
Csd                   Flatten the digit string, and convert from base 256.
%   409                Modulo that by 409
%       hT              and then by 11. All digits go to a distinct num mod 11.
."/9Àøw"                        The compressed string "03924785/61".
@                                Index into that string.
s                                Flatten and implicitly output.


Try it here.

• Cool, basically looks like my approach but far shorter! – Lynn Feb 15 '16 at 20:08
• @Lynn Sorry about that; there's basically one shortest way to do this in Pyth. – lirtosiast Feb 15 '16 at 20:09

# Ruby, 184 bytes

a=0
l=$<.map{|x|x.bytes.map{|y|y==32?0:1}+[0]*2} (0..l[0].count-1).map{|i|l[0][i]+2*l[1][i]+4*l[2][i]}.each{|x| x>0?(a=x+2*a):(p Hash[[40,6,32,20,18,26,42,8,44,64].zip(0..9)][a];a=0)}  ## Explanation • takes the input from stdin • converts the strings to binary sequences, 1/0 for segment on/off • encodes columns to 3bit binary number • encodes sequences of 3 bit numbers to 9 bit numbers, use '0' columns as stop symbols • use a lookup table to convert the 9 bit numbers to digits This is my first code-golf. Thanks for the fun! • Welcome to PPCG! Very nice job on your first post! – J Atkin Feb 15 '16 at 18:11 # Pyth, 39 bytes sm@"413-928-506--7"%%Crd6C\524cjbC.z*3d  This seems to work? Try it online. # Japt, 119 bytes Ur"[|_]"1 z r" + "R x1 qR² £"11 1 1 1151151 111 15111 115 1 1 115 1 111 1511 111 15 1 11511 111 115 1 111 11"q5 bXÃq  Try it here! Oh geez, this one's really long. I don't think I have finished golfing. # Explanation ## Preparation We take the input and convert any |_ to 1. Then we transpose, strip out ending spaces, and split along double-newlines. ## Translation We map over the resulting array and find the index where the form appears in a reference array. Here's a diagram to help: MAPITEM 11 1 1 --> This same form appears at index 0 in the reference array 11 | | V change the mapitem to 0!  After that, we join the array of numbers and output! NOTE: You may be wondering why we have to change each art character to a series of 1's. This is because there seems to be a bug (or something like that) which doesn't let me store the characters as is with |_. • I noticed the _ bug, but I don't know what caused it. – ETHproductions Feb 14 '16 at 23:47 • OK, "\n\n" can be replaced with R², and "\\||_" with "%||_". I think you could also save some bytes by encoding the long string in base 4 (changing each of the 4 disinctive chars to 0, 1, 2, or 3, padding to a length of a multiple of 4, then running r"...."_n4 d} over it), but for some reason, I haven't gotten this to work yet. – ETHproductions Feb 15 '16 at 20:18 # Python2, 299261 244 bytes s=lambda a,i=0:[a]if i==len(a[0])else[[j[:i]for j in a]]+s([j[i+1:]for j in a])if all(j[i]==' 'for j in a)else s(a,i=i+1) p=lambda l:['95572431508448853268'.find(sum(ord(c)**i for i,c in enumerate("".join(n)))%108)/2for n in s(l.split('\n'))]  I really liked this challenge, good job ! ## Explanation The function s takes the three lines as input, it tries to find a digit separation (all characters are spaces). When such a separation is found it calls s with the rest of the three lines and add the value returned by the call to the three lines that compose the digit. If there is no separation it means there is only one digit. The function p is the entry point so it takes a string that represent the digits. The digits are stored as a "hash" computed with sum(ord(c)**i for i,c in enumerate("".join(n)))%108 to save space (thanks to other answers !). ## Exemple digits=""" _ _ | | | _| |_| | |_ """[1:] # remove the '\n' at the beginning p(digits) # [0, 1, 2]  ## Other versions 261 bytes (py3): s=lambda a,i=0:[a]if i==len(a[0])else[[j[:i]for j in a]]+s([j[i+1:]for j in a])if all(j[i]==' 'for j in a)else s(a,i=i+1) def p(l):[print([91,21,84,31,58,76,88,41,80,68].index(sum(ord(c)**i%20 for i,c in enumerate("".join(n)))),end="")for n in s(l.split('\n'))]  249 bytes, this one transpose the lines (py2): f="".join s=lambda a,i=0:[a]if i==len(a)else[a[:i]]+s(a[i+1:])if all(c==' 'for c in a[i])else s(a,i=i+1) h=lambda s:ord(s[0])**len(s)+h(s[1:])if s else 0 p=lambda l:["10220907112527153129".index(h(f(map(f,n)))%34)/2for n in s(zip(*l.split('\n')))]  # JavaScript (ES6), 169 bytes a=>[...(a=a.split )[0]].map((b,c)=>(d={' ':0,'|':1,'_':2})[b]+d[a[1][c]]*2+d[a[2][c]]).join.split(0).map(b=>[343,3,182,83,243,281,381,23,383,283].indexOf(+b)).join  Starts by splitting into three lines, remapping each column into a value, and then building a unique identity for each column from those values. It then splits by 0 (the identity for the space between columns), and finally maps each identity to it's number values, which it concatenates and outputs. • Very nice! I wish python had a list split function... – J Atkin Feb 16 '16 at 17:06 • @JAtkin I joined into a string so that I could split it. I believe you could do that in Python as well? – Mwr247 Feb 16 '16 at 17:20 # Python 3, 281 254 bytes ## Edit I just looked at the code for the other python answer and noticed that much of the code is similar. This was arrived at independently. (newlines added for "readability") def p(i): n=[[]] for l in zip(*i.split('\n')): if all(i==" "for i in l):n+=[[]] else:n[-1]+=l return''.join(map(lambda l:str([''.join(l[2:])==x for x in "|_ _ ||,|,|___ | ,_ ||, _ ||, ___ |,|___ |, ||,|___ ||, ___ ||" .split(',')].index(1)),n))  Ungolfed: def parse(input): lines = list(input.split('\n')) numbers = [[]] for lst in zip(*lines): if all(i==" " for i in lst): numbers += [[]] else: numbers[-1] += lst return ''.join(map(digit, numbers)) def digit(num): fingerprint = "|_ _ ||,|,|___ | ,_ ||, _ ||, ___ |,|___ |, ||,|___ ||, ___ ||".split(',') return str([''.join(num[2:]) == y for y in fingerprint].index(True))  Tests: assert (parse(" _ _ _ _ _ _ \n| | | | | | | | | | | | |\n| |_| |_| |_| |_| |_| |_|") == '1000000') assert (parse(" _ _ \n| |_| |_| |_ \n| _| | _|") == '1945') assert (parse(" _ _ _ \n _| | | | |_ \n|_ |_| | |_|") == '2016') assert (parse(" _ _ _ _ _ _ _ _ \n| | | _| _| |_| |_ |_ | |_| |_|\n|_| | |_ _| | _| |_| | |_| _|") == '0123456789') assert (parse(" _ _ _ \n| | | |_ \n| | | |_|") == '1776')  ## How it works (Note: I am explaining the ungolfed program here since it is more readable and it has the exact same code, with the exception that the digit function is in-lined into a lambda) def parse(input): lines = list(input.split('\n')) numbers = [[]]  The main function is parse. It first splits the input into lines and creates the numbers array.  for lst in zip(*lines): if all(i==" " for i in lst): numbers += [[]] else: numbers[-1] += lst  This is my favorite part (since it took so long to figure out). Here we zip the lines so we can basically vertically traverse the input. When the line has chars on it we add it to the last number in the numbers array. If it does not have any chars on it we add a new number to the array.  return ''.join(map(digit, numbers))  Really simple, numbers is mapped with the digit function and is converted to a string. def digit(num): fingerprint = "|_ _ ||,|,|___ | ,_ ||, _ ||, ___ |,|___ |, ||,|___ ||, ___ ||".split(',') return str([''.join(x[2:]) == y for x, y in zip([num]*10, fingerprint)].index(True))  This is (fairly) simple. fingerprint is the string representation of the digits created above minus the first 2 chars (this was the smallest fingerprint I could find). We return the index of the first match. # Haskell, 270 207 bytes Don't be too hard, this is my first ever haskell program ;) I'm almost certain this can be golfed further, but I don't know how given my limited knowledge of the language. import Data.Lists b n=map c$splitOn["   "]$transpose$lines n
c n|e<-drop 2$concat n,Just r<-elemIndex True[e==f|f<-splitOn",""|_ _ ||,|,|___ | ,_ ||, _ ||, ___ |,|___ |, ||,|___ ||, ___ ||"]=(show r)!!0  Ungolfed: module Main where import Data.Lists main :: IO () main = print$ parse " _     _  _       _   _  _   _   _ \n| | |  _| _| |_| |_  |_   | |_| |_|\n|_| | |_  _|   |  _| |_|  | |_|  _|"

parse :: String -> String
parse n = let lst = transpose $lines n numbers = splitOn [" "] lst --" " lst number = map digit numbers in number digit :: [String] -> Char digit n | e <- drop 2$ intercalate "" n
, fingerprint <- ["|_ _ ||","|","|___ | ","_ ||","  _  ||"," ___  |","|___  |","  ||","|___ ||"," ___ ||"]
, Just res <- elemIndex True [e == finger | finger <- fingerprint]
= head $show res  Big thanks to @nimi for the tips! • bad news first: I'm afraid you have to include the import Data.List in your byte count. Good news: a) if you have Data.Lists installed you can import it instead and replace a with splitOn: ...map c$splitOn[" "]$transpose... and ...f<-splitOn",""|_.... b) intercalate "" n is concat n or id=<<n. c) replace res with a single letter name. d) use pattern guards instead of let ... in: c n|e<-drop 2$id=<<n,Just r<-elemIndex ... ]=(show r)!!0. – nimi Feb 16 '16 at 22:51
• Hehehe, Whoops! The import was lost in the copy/paste ;) Thanks for all the tips! – J Atkin Feb 16 '16 at 23:01
• @nimi Sorry to bother you about it, but do you mind explaining what =<< does? Neither the hoogle docs or the type signature are very helpful to me. – J Atkin Feb 17 '16 at 0:33
• =<< in list context is concatMap, i.e. it maps the given function over the list and combines the results into a single list. >>= does the same but with the arguments flipped. id =<< n (or n >>= id) maps the identity function over the list (of lists), i.e. does nothing with the sublists and the concatenates them. So it's the same as concat. – nimi Feb 17 '16 at 6:30