text:
Read ASCII-Art Text
Inspired by Golf me an ASCII Alphabet, of which this challenge is (almost) a direct inverse.

Task:
Take a string of ASCII-art text and output the content of the text as regular ASCII text.

Input:
String of ASCII-art text.
Input will only contain instances of ASCII character #, spaces and 4 or 5 newlines (a trailing newline is optional). All lines have the same length. (That is, the last ASCII-art letter is padded with trailing spaces.) You can use some other printable ASCII character instead of # in the input if you wish.
The input will contain ASCII-art letters A-Z and ASCII-art spaces (a 5x5 block of whitespace). No punctuation. There is only one line of ASCII-art text (5 actual lines). There will be no trailing or leading ASCII-art spaces, nor will there be adjacent ASCII-art spaces.
Letter size is 5x5 characters. There is a 1x5 space between each letter. Space between words is a 5x5 block of whitespace (+ 1x5 space on each side, because it is just another letter). There will be no 1x5 space at the end or at the beginning, only between ASCII-art letters.

Output:
String containing the text as ASCII characters A-Z + spaces. The output can be in lowercase also, if that is somehow easier for your solution. Mixed case is also allowed.

The ASCII-art letters:
 ###  ####   ###  ####  ##### #####  ###  #   # ##### ##### #   # #     #   #
#   # #   # #   # #   # #     #     #     #   #   #     #   #  #  #     ## ##
##### ####  #     #   # ####  ####  #  ## #####   #     #   ###   #     # # #
#   # #   # #   # #   # #     #     #   # #   #   #   # #   #  #  #     #   #
#   # ####   ###  ####  ##### #      ###  #   # ##### ###   #   # ##### #   #

#   #  ###  ####   ###  ####   ###  ##### #   # #   # #   # #   # #   # #####
##  # #   # #   # #   # #   # #       #   #   # #   # #   #  # #   # #     #
# # # #   # ####  #   # ####   ###    #   #   #  # #  # # #   #     #     #
#  ## #   # #     #  #  #   #     #   #   #   #  # #  ## ##  # #    #    #
#   #  ###  #      ## # #   #  ###    #    ###    #   #   # #   #   #   #####

The space:
     |
     | A 5x5 square of spaces.
     | (Padded with |s to make it appear in this post.)
     |
     |

Examples:
Input:
#   # ##### #     #      ###        #   #  ###  ####  #     ####
#   # #     #     #     #   #       #   # #   # #   # #     #   #
##### ####  #     #     #   #       # # # #   # ####  #     #   #
#   # #     #     #     #   #       ## ## #   # #   # #     #   #
#   # ##### ##### #####  ###        #   #  ###  #   # ##### ####

Output: HELLO WORLD
Input:
 ###   ###   ###  ##### #####
#   # #     #   #   #     #
#####  ###  #       #     #
#   #     # #   #   #     #
#   #  ###   ###  ##### #####

Output: ASCII
Input:
####  ####   ###   ###
#   # #   # #   # #
####  ####  #     #  ##
#     #     #   # #   #
#     #      ###   ###

Output: PPCG

This is code-golf, so the shortest answer in bytes wins.

I'm thinking the solution to this might involve some sort of hash function...

Bounty from me if you do this by converting the input to an image and solves this using image processing! (The solution must be golfed too of course)

If it's of help to anyone: either the second row, the fourth row, or the middle column of the letters can be dropped without losing relevant information.

Can we take 0 instead of a space?

@JungHwanMin Hmm. I think not, because that would not be very human-readable ASCII-art text.

You mention that the result may be lowercase, how about mixed case?

Related

Is it ok to require \n for newlines instead of the newline character?

@JonathanAllan I guess that would be ok, too.

@agtoever I'd say no, because that wouldn't be very readable ASCII-art text.

@agtoever To be more precise about this, yes, including '\n' in a string literal in the code would be fine, as in a C string literal "line 1\nline 2", but a string including '\' and 'n' as separate characters would not be okay.

@agtoever If this is what you meant all along, then I misunderstood your question, sorry.

Do newlines have to be handled?

@carusocomputing Like this? No.

Jelly,  50 44  42 bytes
ỴZ;6/UOḂḅ7‘ị“¥ŒƲVĊ⁾|W£⁼³ƭÇuʋụzḢĖ0ḢẆẠØsĠỌỊ»

Try it online! (note the argument does not require the leading newline, but since leading and trailing newlines have no effect I included one to make the multiline string more human-readable)
Results are mixed case (as allowed by the OP in a comment).
How?
Splits on new lines, transposes, and joins together sub-slices of (up to) six together to get the character representations and reverses each (equating the later base conversion for the final character of length 25 to all the others of length 30). Then maps '#' and ' ' to one and zero respectively using the fact that '#' has an odd ordinal while ' ' has an even one. Reads each as if it were a base seven number. Effectively takes modulo 81 of each (to yield 27 unique values for the 27 possible cases), and finally indexes into a "magic string" with the correct chars at the correct indexes (modulo indexing is used with a magic string of length 81 to save 2 bytes).
Here is the "magic string" I created along with a (case-insensitive) regex pattern it needed to match (I added "ed" to make it length 81):
 ' affectedly Azerbaijan rewaxed naganas jiujitsudankly pase UVB freqHaarlemcoacted'
'^ ..f...e.....z......a..r.w.x...n.g......iuj....d..kly.p.s...vb....qh.....m.o.ct.*'

As such it may be compressed, looking up eleven sub-slices as words in Jelly's dictionary (most of which use the leading space default):
' affectedly Azerbaijan rewaxed naganas jiujitsudankly pase UVB freqHaarlemcoacted'
 ^          ^          ^       ^       ^        ^     ^    ^   ^    ^      ^

which results in the Jelly compressed string, “¥ŒƲVĊ⁾|W£⁼³ƭÇuʋụzḢĖ0ḢẆẠØsĠỌỊ»
The rest of the code works as follows:
ỴZ;6/UOḂḅ7‘ị“...» - Main link: multi-line string, s   e.g. HI as the #s and spaces
Ỵ                 - split on new lines                     ["#   # #####","#   #   #  ","#####   #  ","#   #   #  ","#   # #####"] (each is actually a list)
 Z                - transpose                              ["#####","  #  ","  #  ","  #  ","#####","     ","#   #","#   #","#####","#   #","#   #"] (each is actually a list)
   6/             - six-wise reduce by
  ;               -     concatenation                      ["#####  #    #    #  #####     ","#   ##   #######   ##   #"] (each is actually a list)
     U            - upend (reverse each)                   ["     #####  #    #    #  #####","#   ##   #######   ##   #"] (each is actually a list)
                  -     note: all except the last will be length 30 and like "     ...", which will become [0,0,0,0,0,...], while the last will be length 25 without those five leading zeros.
      O           - cast to ordinals ('#' -> 35, ' '-> 32) [[32,32,...],[35,32,...]]
       Ḃ          - modulo 2 ('#' -> 1, ' ' -> 0)          [000001111100100001000010011111, 1000110001111111000110001] (each is actually a list)
        ḅ7        - convert from base 7 (vectorises)       [223498370543967315553, 191672428080864454753] (these are now integers)
          ‘       - increment                              [223498370543967315554, 191672428080864454754]
                  -  (modulo 81 these would be [68, 41])
           ị      - index into (modulo & 1-indexed):
            “...» -     the "magic string" described above ' affectedly Azerbaijan rewaxed naganas jiujitsudankly pase UVB freqHaarlemcoacted'
                                                           "Hi"                                   41^                        68^

Python 2, 405 335 234 182 171 bytes
lambda s,j=''.join:j(' QPVXU_O__FBLK_JMD_CSYZWIENH_AG___TR'[int(j(`ord(y)%2`for y in j(s.split('\n')[x][i:i+5]for x in range(5))),2)%13836%37]for i in range(0,len(s)/5,6))

Try it online!

Finally shorter than JS

Clever use of the modulus, but I can't help thinking there must be a way to do: [0,2,3,7,...] and ' UBGOTA... split it, and use some sort of mapping. 0:' ',2:'U',3:'V'... looks so long,,, there are so many :'',. (I know you had something similar in the original post, but with very long numbers.

@StewieGriffin it is better now

JavaScript (ES6), 204 186 184 182 bytes
Saved 18 bytes thanks to Neil
Saved 2 bytes thanks to ETHproductions
Saved 2 bytes thanks to YairRand
Breakdown:

42-byte lookup table
162 144 142 140 bytes of code

s=>(a=s.split`
`)[0].replace(/.{6}/g,(_,n)=>' H_JM__WDCSORLU___QKG_P_AFT_N_EI_XBV____YZ'[[0,1,2,4].reduce((p,r,i)=>p+='0b'+a[r].substr(n,5).replace(/./g,c=>1^1-c)<(a=s.split`
`)[0].replace(/.{6}/g,(_,n)=>' H_JM__WDCSORLU___QKG_P_AFT_N_EI_XBV____YZ'[[0,1,2,4].reduce((p,r,i)=>p+='0b'+a[r].substr(n,5).replace(/./g,c=>1^1-c)<<i*6,0)%178%69%43])

console.log(f(
  ' ###   ###   ###  ##### ##### \n'+
  '#   # #     #   #   #     #   \n'+
  '#####  ###  #       #     #   \n'+
  '#   #     # #   #   #     #   \n'+
  '#   #  ###   ###  ##### ##### \n'
));

You can save a whole bunch of bytes using (a=s.split`\n`)[0].replace(/......?/g, with substr(n,5) and without the join of course.

I think you can save a byte with c=>0|c>' ', and another with p+='0b'+...

As mentioned by @Steadybox in the Comment section of the Challenge, taking \n in input is invalid. However, I think you can use template literal with actual newline as input, just like you are doing in the split method.

@DobbyTheFree-Elf I could indeed use a template literal -- which incidentally would impair the readability because of the leading quote. But adding a constraint on the way the input data is formatted before being passed to the function is out of topic, IMHO (as long as the actual content of the input is valid).

@DobbyTheFree-Elf I'm afraid my comment was a bit ambiguous, and I may have slightly misunderstood the question I was answering. Using \n in a string literal at the call site in the code is okay, because the actual string that is passed to the function includes only the newline character, not both \\ and n. Passing a string that contains \\ and n as separate adjacent characters would not be okay.

You can save two bytes by replacing 0|c>' ' with 1^1-c.

Bash + ImageMagick + Tesseract, 161 bytes
I wanted to try the approach suggested by @stewie-griffin and went for bash + ImageMagick (to convert a string to an image) and Tesseract (to do the OCR). Here's my code, which works for the 'HELLO WORLD' testcase, but fails the other ones. Maybe some tweaking to the parameters (font, font size, kerning, spacing) helps.
convert -font Courier-Bold -pointsize 8 -interline-spacing -3 -kerning -3 label:"$(</dev/stdin)" -bordercolor White -border 5%x20% png:- | tesseract stdin stdout

Just copy-paste the ascii art into the commandline after running the command. Finish your input by pressing ^d.
Current output for the test cases:

HELLO WORLD: HELLO WORLD
ASCII: H5511
PPCG: PPOG

Scala, 184 181 bytes
A magic string + modulo solution based on hashCode :)
(a:String)=>a.split("\n").map(_.grouped(6)map(_.take(5))toArray).transpose.map(l=>"Q__WLUY_XOI_ZN_GEFR_P__JKBMV_S__ __C__D__H_T__A"(Math.abs(l.mkString.hashCode)%106%79%47))mkString

Try online (Scalafiddle)
More readable :
(a:String) => a.split("\n")
                .map(_.grouped(6)map(_.take(5))toArray)
                .transpose
                .map ( l =>
                    "Q__WLUY_XOI_ZN_GEFR_P__JKBMV_S__ __C__D__H_T__A"(
                        Math.abs(l.mkString.hashCode)%106%79%47
                    )
                )mkString

Explanations

The initial String (ASCII art) is split into 5 lines (height of ASCII character)
Each line is split in 6-characters elements (width of ASCII character + 1 space)
Only the first 5 characters are kept (the space at the end is useless)
The lines are transposed (each ASCII character is represented as a sequence of 25 characters (5x5), containing either '#' or ' ')
Each ASCII character representation (sequence) is converted to String and an absolute hashcode is computed for that String (absolute needed because of next modulus)
3 consecutive modulus (% 106 % 79 % 47) are applied to associate a number ∈ [0; 47[ for each ASCII character (see explanations below)
This number is used as an index of the magic string

How to get the magic string ?
First, I represented all letters like this :
case class Letter(letter: Char, ascii: Seq[Char])

Then, I created an alphabet containing ASCII representations of all characters :
Example :
 ###
#   #
#####
#   #
#   #

becomes
Letter('A', " ### #   #######   ##   #") // 25 characters from top-left to bottom-right

For each letter, an absolute hashcode was computed (all hashcodes are distinct) :
val codes = alphabet.map { case Letter(l, a) => (l, Math.abs(a.mkString.hashCode)) }
// codes: Seq[(Char, Int)] = List(( ,253243360), (A,380997542), (B,1221679148), (C,1573119535), (D,307929190), (E,858088672), (F,857996320), (G,750155628), (H,897290147), (I,1518088099), (J,928547488), (K,1184149391), (L,519601059), (M,741735953), (N,2139154001), (O,1625960980), (P,1307658950), (Q,92382816), (R,1221771494), (S,1689301359), (T,1515228067), (U,1390718627), (V,386730851), (W,733134481), (X,628338619), (Y,23919695), (Z,2081560145))

Then I tried to decrease each code, but always respecting the fact that each code must be unique (the list grouped by the code must have 27 elements, 1 for each letter). So I tried the first 200 modulus :
val mod = (1 to 200).find(modulo => codes.map { case (a,b) => (a, b % modulo) }.groupBy(_._2).size==27).get

I found 106 as the first modulo to be applied :
val codes2 = codes.map { case (l, c) => (l, c%mod) }
val codes = codes2
// codes: Seq[(Char, Int)] = List(( ,32), (A,46), (B,104), (C,35), (D,38), (E,16), (F,96), (G,94), (H,41), (I,89), (J,102), (K,71), (L,83), (M,105), (N,13), (O,56), (P,20), (Q,0), (R,18), (S,29), (T,43), (U,5), (V,27), (W,3), (X,87), (Y,53), (Z,91))

I repeated the previous steps until the smallest modulo. I found :

79
47
44
42

Note : The last modulo I chose (47) is not the smallest here :

I found 44, but if I had chosen 44, the magic string would have size 44 (instead of 47) but I would have to write %106%79%47%44 (13 characters instead of %106%79%47 = 10 characters). So in bytes, the code should have had the same size as the one I got
There is also 42, but then the code should have had 1 byte more than the one I got

Next, I applied the consecutive modulus (% 79 % 47) to the last codes, to get the definitive codes associated to each letter :
codes: Seq[(Char, Int)] = List(( ,32), (A,46), (B,25), (C,35), (D,38), (E,16), (F,17), (G,15), (H,41), (I,10), (J,23), (K,24), (L,4), (M,26), (N,13), (O,9), (P,20), (Q,0), (R,18), (S,29), (T,43), (U,5), (V,27), (W,3), (X,8), (Y,6), (Z,12))

Finally, to construct the magic string :
val initialMap = (0 until 47).map(i => (i, '_')).toMap
val codesMap = codes.map(i => (i._2, i._1)).toMap

val magicString = (initialMap ++ codesMap).toSeq.sortBy(_._1).map(_._2).mkString
// magicString: String "Q__WLUY_XOI_ZN_GEFR_P__JKBMV_S__ __C__D__H_T__A"

Example : The letter A above is associated to 46 (380997542 % 106 % 79 % 47), and the 46th element of the magic string is A :)
Test cases
// assign function to f
val f = (a:String)=>a.split("\n").map(_.grouped(6)map(_.take(5))toArray).transpose.map(l=>"Q__WLUY_XOI_ZN_GEFR_P__JKBMV_S__ __C__D__H_T__A"(Math.abs(l.mkString.hashCode)%106%79%47))mkString

HELLO WORLD :
val asciiArt = """|#   # ##### #     #      ###        #   #  ###  ####  #     ####
                  |#   # #     #     #     #   #       #   # #   # #   # #     #   #
                  |##### ####  #     #     #   #       # # # #   # ####  #     #   #
                  |#   # #     #     #     #   #       ## ## #   # #   # #     #   #
                  |#   # ##### ##### #####  ###        #   #  ###  #   # ##### #### """.stripMargin

f(asciiArt)    // HELLO WORLD

ASCII :
val asciiArt = """| ###   ###   ###  ##### #####
                  |#   # #     #   #   #     #
                  |#####  ###  #       #     #
                  |#   #     # #   #   #     #
                  |#   #  ###   ###  ##### #####""".stripMargin

f(asciiArt)    // ASCII

PPCG :
val asciiArt = """|####  ####   ###   ###
                  |#   # #   # #   # #
                  |####  ####  #     #  ##
                  |#     #     #   # #   #
                  |#     #      ###   ### """.stripMargin

f(asciiArt)    // PPCG

Edits

Saved 3 bytes by removing . before map, toArray and mkString

PHP, 294 Bytes
<?$l=" 00000YE00G0000R000A0Q0000C0BW000K00000000000LT00000J00000000MU0000Z0000DI000000V0000000P00H0000ONF000S00X";preg_match_all("#(.{5})\s#s","$_GET[0] ",$t);for($i=0;$i<$c=count($a=$t[1])/5;$i++)$s.=$l[bindec(strtr($a[$i].$a[$i+$c].$a[$i+2*$c].$a[$i+3*$c].$a[$i+4*$c]," #","01"))%106];echo$s;

Try it online!
Expanded
$l=" 00000YE00G0000R000A0Q0000C0BW000K00000000000LT00000J00000000MU0000Z0000DI000000V0000000P00H0000ONF000S00X"; # search string mod 106
preg_match_all("#(.{5})\s#s","$_GET[0] ",$t); # Regex take each group of five chars followed by a whitespace
for($i=0;$i<$c=count($a=$t[1])/5;$i++)
  $s.=$l[bindec(strtr($a[$i].$a[$i+$c].$a[$i+2*$c].$a[$i+3*$c].$a[$i+4*$c]," #","01"))%106]; # join each groups make a binaray make a decimal mod 106
echo$s; # Output

Converting the Input to an image format
@Stevie Griffin search a solution to get this from an image.
I think he want not really the image format I have use.
echo'<svg xmlns="http://www.w3.org/2000/svg" width="100%"><switch><foreignObject x="0" y="0" width="100%" height="300">
'.$_GET[0].'
</foreignObject></switch></svg>';

SVG can contains HTML parts if then included in a foreignObject.
So I put a pre Element in a SVG.
Image Output

<svg xmlns="http://www.w3.org/2000/svg" width="100%"><switch><foreignObject x="0" y="0" width="100%" height="300">
#   # ##### #     #      ###        #   #  ###  ####  #     ####
#   # #     #     #     #   #       #   # #   # #   # #     #   #
##### ####  #     #     #   #       # # # #   # ####  #     #   #
#   # #     #     #     #   #       ## ## #   # #   # #     #   #
#   # ##### ##### #####  ###        #   #  ###  #   # ##### ####
</foreignObject></switch></svg>

Solving from Image Changes
SVG is machine readable so after saving the SVG as "i.svg" you need
only replace $_GET[0] with preg_replace("#(^.*e>)(.*)(</p.*$)#s","$2",join(file("i.svg"))) in the way with normal input + 55 Bytes

Thanks for the brilliant solution. Can you please further explain how to calculate the value of variable $l, I want to calculate it for the 3 columns instead of 5. Thanks

C,  225  209 bytes
Thanks to @ceilingcat for saving 16 bytes!
i,j,k,l,n,m;f(char*s){l=index(s,10)-s+1;for(i=0;i<l/6;++i){for(m=j=0;j<5;m+=n*(exp10(j++)+.1))for(n=k=0;k<5;)n+=(s[i*6+j+k*l]==35)<<k++;for(j=0;"Qi Y$>W);Xa%d^F4K-]7jcMAG="[j++]-32-m%77;);putchar(n?64+j:32);}}

Try it online!

Powershell, 152 146 bytes
-join$(for($t=$args-split'
';$c-lt$t[0].Length;$c+=6){$s=0;$t|% s*g $c,5|% t*y|%{$s+=$s+$_}
'_ISRJ_BK_HFQPL_MYNCE _TXDAO_VWUZ__G'[$s%578%174%36]})

Test script:
$f = {

-join$(for($t=$args-split'
';$c-lt$t[0].Length;$c+=6){$s=0;$t|% s*g $c,5|% t*y|%{$s+=$s+$_}
'_ISRJ_BK_HFQPL_MYNCE _TXDAO_VWUZ__G'[$s%578%174%36]})

}

&$f @"
#   # ##### #     #      ###        #   #  ###  ####  #     ####
#   # #     #     #     #   #       #   # #   # #   # #     #   #
##### ####  #     #     #   #       # # # #   # ####  #     #   #
#   # #     #     #     #   #       ## ## #   # #   # #     #   #
#   # ##### ##### #####  ###        #   #  ###  #   # ##### ####
"@

&$f @"
 ###   ###   ###  ##### #####
#   # #     #   #   #     #
#####  ###  #       #     #
#   #     # #   #   #     #
#   #  ###   ###  ##### #####
"@

&$f @"
####  ####   ###   ###
#   # #   # #   # #
####  ####  #     #  ##
#     #     #   # #   #
#     #      ###   ###
"@

&$f @"
       ###  ####   ###  ####  ##### #####  ###  #   # ##### ##### #   # #     #   # #   #  ###  ####   ###  ####   ###  ##### #   # #   # #   # #   # #   # #####
      #   # #   # #   # #   # #     #     #     #   #   #     #   #  #  #     ## ## ##  # #   # #   # #   # #   # #       #   #   # #   # #   #  # #   # #     #
      ##### ####  #     #   # ####  ####  #  ## #####   #     #   ###   #     # # # # # # #   # ####  #   # ####   ###    #   #   #  # #  # # #   #     #     #
      #   # #   # #   # #   # #     #     #   # #   #   #   # #   #  #  #     #   # #  ## #   # #     #  #  #   #     #   #   #   #  # #  ## ##  # #    #    #
      #   # ####   ###  ####  ##### #      ###  #   # ##### ###   #   # ##### #   # #   #  ###  #      ## # #   #  ###    #    ###    #   #   # #   #   #   #####
"@

Output:
HELLO WORLD
ASCII
PPCG
 ABCDEFGHIJKLMNOPQRSTUVWXYZ

Note:

$t|% s*g $c,5|% t*y|%{$s+=$s+$_} is shortcut for $t.substring($c,5).toCharArray()|%{$s+=$s+$_}
("abcd","efgh").substring(1,2) returns the array ("bc","de")
("bc","de").toCharArray() returns the array ('b','c','d','e')


text:
Let's do some "deciph4r4ng"
In this challenge, your task is to decipher a string. Luckily, the algorithm is pretty simple: reading from left to right, each encountered digit N (0 to 9) must be replaced with the character which is N+1 positions before it.
Example
The input string "Prog2am0in6" would be decoded this way:

Hence, the expected output is "Programming".
Clarifications and rules

The input string will contain ASCII characters in the range 32 - 126 exclusively. You can assume that it will never be empty.
The original deciphered string is guaranteed not to contain any digit.
Once a character has been decoded, it may in turn be referenced by a subsequent digit. For instance, "alp2c1" should be decoded as "alpaca".
References will never wrap around the string: only previous characters can be referenced.
You can write either a full program or a function, which either prints or outputs the result.
This is code golf, so the shortest answer in bytes wins.
Standard loopholes are forbidden.

Test cases
Input : abcd
Output: abcd

Input : a000
Output: aaaa

Input : ban111
Output: banana

Input : Hel0o W2r5d!
Output: Hello World!

Input : this 222a19e52
Output: this is a test

Input : golfin5 3s24o0d4f3r3y3u
Output: golfing is good for you

Input : Prog2am0in6 Puz0les7&1Cod74G4lf
Output: Programming Puzzles & Code Golf

Input : Replicants 4re3lik448ny3oth8r5mac6in8.8T64y'r371it9376a1b5n1fit7or2a1h2z17d.
Output: Replicants are like any other machine. They're either a benefit or a hazard.

Can we receive the input as an array of single character strings? Can we assume that the number will never be greater than 9?

@fəˈnɛtɪk Regarding the input format: I'd say no, unless this is the only acceptable format for your language. We're dealing with single digits rather than numbers. So yes: it's guaranteed to be <= 9 but you may encounter several digits in a row.

Would 1bbab be a valid input (with expected output of abbab)? In other words, can the references wrap around the string?

@Luke Good point. No, 1bbab is not valid. I've added a clarification about that.

Jelly, 9 7 bytes
~ịṭṭµ@/

Try it online!
How it works
~ịṭṭµ@/  Main link. Argument: s

    µ    Combine the four links to the left into a chain (arity unknown).
     @   Swap the chains arguments. This makes it dyadic.
      /  Reduce s by the chain with swapped arguments. It will be called with
         right argument r (the result of the previous call, initially the first
         character) and left argument c (the next character of s).
~            Bitwise NOT of c. This maps a digit 'd' to ~d = -(d+1), but all
             non-digit characters 'D' to 0.
  ṭ          Tack; append c to r.
 ị           Index; select the character of the result to the right at the
             index from the result to the left. Indexing is 1-based and modular,
             so 0 is the last character, -1 the second to last, etc.
   ṭ         Tack; append the resulting character to r.

Java 7, 81 80 bytes
void a(char[]a){for(int i=0;++i<a.length;)if(a[i]>47&a[i]<58)a[i]=a[i-a[i]+47];}

Try it online!
Saved 1 byte thanks to Anders Tornblad. The first character cannot be a digit so it doesn't need to be checked meaning we can preincrement before checking our terminate condition.

Since the first char could never contain a digit, you don't have to check it. Therefore, your loop can be for(int i=0;++i<a.length;){ instead, saving one char.

Haskell, 55 bytes
o#c|c>'/',c<':'=o!!read[c]:o|1<2=c:o
reverse.foldl(#)[]

Usage example: reverse.foldl(#)[] $ "Prog2am0in6 Puz0les7&1Cod74G4lf" -> "Programming Puzzles & Code Golf". Try it online!
Reduce the string to a reverse copy of itself with the numbers replaced by the corresponding chars. "reverse", because this way we have easy access to the string so far when indexing the numbers. Reverse it again.

Wow, I have written this exact solution but I was slow in posting it :) Well, at least now I know it was a good one, +1

C, 46 bytes
f(char*s){for(;*s++;)*s=s[(*s-52)/6?0:47-*s];}

Try it online!

C,  52   49  48 bytes
Thanks to @l4m2 for saving a byte!
f(char*s){for(;*s++;)*s>47&*s<58?*s=s[47-*s]:0;}

Edits the input string directly.
Try it online!
Alternative 50-byte version:
f(char*s){for(;*s++;)*s=abs(*s-57)>9?*s:s[47-*s];}

Recursive version, 48 bytes:
f(char*s){*s>47&*s<58?*s=s[47-*s]:0;*s++&&f(s);}

05AB1E, 11 bytes
vydiÂyèëy}J

Try it online!
Explanation
v            # for each character y in input
 ydi         # if y is a digit
    Â        #    push a reversed copy of the string we've built up so far
     yè      #    push the character at index y in the reversed string
       ë     # else
        y    #    push y
         }   # end if
          J  # join stack to a single string
             # output top of the stack at the end of the loop

I really need to check to see if you've already answered more often before starting.

@carusocomputing: You could still think up some better trick than I've used ;)

JavaScript (ES6), 59 53 bytes
f=x=>/\d/.test(x)?f(x.replace(/\d/,(m,o)=>x[o+~m])):x

Saved 7 bytes thanks to fəˈnɛtɪk.

f=x=>/\d/.test(x)?f(x.replace(/\d/,(m,o)=>x[o+~m])):x

console.log(f("Prog2am0in6"));
console.log(f("abcd"));
console.log(f("a000"));
console.log(f("ban111"));
console.log(f("Hel0o W2r5d!"));
console.log(f("this 222a19e52"));
console.log(f("golfin5 3s24o0d4f3r3y3u"));
console.log(f("Prog2am0in6 Puz0les7&1Cod74G4lf"));
console.log(f("Replicants 4re3lik448ny3oth8r5mac6in8.8T64y'r371it9376a1b5n1fit7or2a1h2z17d."));

.charAt(...) can be replaced with [...] for savings of 7 bytes

x.charAt(...) is equivalent to x[...]

@fəˈnɛtɪk Yep, I thought I tried that before but it threw an error. Thanks!

o-m-1 can be replaced with o+~m.

Because f is called recursively, the character count of the program must include the f= part, so this is 54 bytes, not 52.

f=x=>x!=(y=x.replace(/\d/,(m,o)=>x[o+~m]))?f(y):x

You can actually abuse x again: f=x=>x!=(x=x.replace(/\d/,(m,o)=>x[o+~m]))?f(x):x

then x=>f=x!=(x=x.replace(/\d/,(m,o)=>x[o+~m]))?f():x

Retina, 37 bytes
Byte count assumes ISO 8859-1 encoding.
\d
$*«»
r1+`(?<=(.)(?<-2>.)*)(«)*»
$1

Try it online!
Explanation
\d
$*«»

Replace each digit d with d «s, followed by one ». We need the latter a) to be able to recognised positions where d = 0 and b) as a separator between adjacent digits.
r1+`(?<=(.)(?<-2>.)*)(«)*»
$1

Repeatedly (+) match the regex on the first line from right to left (r) and then replace the left-most match (1) with the substitution on the second line.
The regex itself matches one of our now unary digits and counts the number of «s in group 2. The lookbehind then matches d characters with (?<-2>.)* before capturing the referred-to character in group 1. The string of «s and » is then replaced with the captured character.

MATL, 21 19 17 16 bytes
"@t4Y2m?UQ$y]]&h

Try it at MATL Online!
Explanation
        % Implicitly grab input as a string
"       % For each character in the input
  @     % Push that character to the stack
  t     % Make a copy of it
  4Y2   % Push the pre-defined array '0123456789' to the stack
  m     % Check if the current character is part of this array (a digit)
  ?     % If it is
    UQ  % Convert it to a number and add 1 (N)
    $y  % Make a copy of the element N-deep in the stack. MATL uses one-based indexing
        % So 1$y is the element at the top of the stack, 2$y is the next one down, etc.
  ]     % End of if statement
        % Non-digit characters remain on the stack as-is
]       % End of for loop
&h      % Horizontally concatenate the entire stack to form a string
        % Implicitly display the result

Nice use of $y in the new version!

@LuisMendo Thanks! Yea stack-based languages are a good fit for this challenge

@LuisMendo Unfortunately this could have been shortened even more if U only worked for digits. Unfortunately 'e'U yields exp(1) otherwise I could have gotten rid of the 4Y2 stuff

Another of those Octave things...

JavaScript (ES6), 51 bytes

f=
s=>s.replace(/\d/g,(c,i)=>a[i]=a[i+=~c]||s[i],a=[])
<input oninput=o.textContent=f(this.value)><pre id=o>

a is used to store the replaced digits to deal with digits referring to other digits.

s=>s.replace(a=/\d/g,(c,i)=>a[i]=a[i+=~c]||s[i])

Perl 5, 34 bytes
33 bytes of code + -p flag.
s/\d/substr$_,-$&-1+pos,1/e&&redo

Try it online!
s/\d/.../e replace the first digit by ... evaluated as Perl code. (with ... being substr$_,-$&-1+pos,1 in that case. substr$_,-$&-1+pos,1 returns the substring of $_ of length 1 at index -$&-1+pos, where $& is the number just matched, and pos is the index of the start of the match. We just need to redo if the replace was successful in order to replace every digit. (and the result is implicitly printed thanks to -p flag).

Old approach, 47 bytes:
44 bytes of code + -F flag.
map{$F[$i]=$F[$i-$_-1]if/\d/;++$i}@F;print@F

Try it online!
Quite straight forward actually. -F flag splits the inputs on each character into @F. map{...}@F iterates through @F (ie. every character of the input). If the character if a digit (/\d/), then we replace it by the character at index $i-$_-1. The $i is the current index variable (that we maintain by incrementing at each character seen).

JavaScript ES6, 61 59 bytes
Thanks @Luke for golfing off 8 bytes
x=>[...x].map((p,i,a)=>a[i]=/\d/.test(p)?a[i-1-p]:p).join``

Try it online!

x.split\`could also be[...x], [0-9]could be\d`, together saving 6B

Currently has an error somewhere so going to fix that first

x=>[...x].map((p,i,a)=>+p+1?a[i-1-p]:p).join\`` for 46 bytes

Fails for spaces +" " gives 0 which causes it to grab the previous character

x=>[...x].map((p,i,a)=>a[i]=1+p>9?a[i-1-p]:p).join``

05AB1E, 27 17 bytes
vyDdiU)DRXèU`X}}J

Try it online!
vy             }  # For each character
  Dd              #   Push is_number
    i         }   #   If it is
     U            #     Save save it
      )DR         #     Wrap the (reversed) stack into an array
         Xè       #     Get the character at the saved index
           U`X    #     Flatten the whole stack
                J # Join

Python 2, 75 71 bytes
s='';j=-1
for i in input():s+=s[j-int(i)]if'/'<i<':'else i;j+=1
print s

Try it Online!
Edit: Fixed for ascii values between 32-47 ; Fixed for double decoding (eg. "alp2c1" to "alpaca")

@Arnauld Nope. Sorry, i didn't read the spec closely enough. WIll modify shortly

It seems there is a bug. for 'Prog2am0in6 Puz0les7&1Cod74G4lf' your program prints Programming Puzzles &7Code1Golf! I tried with both TIO links shared!

@KeerthanaPrabhakaran Thanks! Fixed at the cost of 0 bytes! (My alternate solution didn't make the cut though)

Thats a great approach!

Can you explain '/'<i<':'. I know it's testing if it's a number but how does it work?

@MatiasK it compares the ascii value of i to / and :. Take a look at this table and you'll see why it works

That is a really neat way to test for integer-ness of a string!

CJam, 13 bytes
q{_A,s#)$\;}/

Online demo.
This solution uses CJam's built-in "copy n-th item on the stack" operator $ to implement the decoding.
It starts by reading the input (with q) and then looping over the characters from the input string and dumping them onto the stack (with {}/).
However, inside the loop body it also duplicates each character after it has been put on the stack (with _) and checks if it's a digit by looking up its position with # in the string "0123456789", conveniently represented as A,s.
The result of this lookup is either the digit's numeric value or, if the character is not a digit, -1.  The ) operator then increments that value by one, and $ replaces it with the character current at that many positions below the top of the stack.  Finally, \; just removes the copy of the current input character that we made with _ from the stack, as it's no longer needed.

Befunge-98, 45 43 bytes
::::#@~\1p:1g::'9`!\'/`*j;'/--1g\1p\1g#;,1+

Try it online!
The idea:

For each char in the input string,

Write it to line 2
If it is not a number, just output it
Otherwise, look up the correct value, rewrite it, then output it

::::            ; There's a counter on the stack, duplicate it 4 times  ;
    #@~         ; Get the next char of input, exiting if there is none  ;
       \1p      ; At the location (counter, 1), write the input char    ;
          :1g   ; Re-obtain the char. Stack is now [counter * 4, input] ;

::                ; Stack: [counter * 4, input * 3]      ;
  '9`!\'/`*       ; If !(input > '9') and (input > '/')  ;
                  ; IE If ('0' <= input && input <= '9') ;
           j;...; ; Then execute the ...                 ;

; Stack: [counter * 4, input] ;
; The ... branch:             ;

'/-             ; input -> int. (input -= '/')             ;
   -            ; counter - int(input) - 1                 ;
                ; Stack: [counter * 3, lookupPosition ]    ;
    1g          ; Get the char that we want to find        ;
      \1p\1g#   ; Overwrite the current char (not the old) ;

; Both branches: ;
,1+             ; Print the number and increment the counter ;

I wasn't able to get this version shorter, but this one is 44 bytes:
s #@~\3p:3g::'9`!\'/`*j;'/--3g#;:10g3p,1+:::

Thought I'd share it because of the neat trick with s - but storing the counter on the stack leads to that 1 char improvement

Python 2, 59 bytes
s=''
for c in input():s+=c['/'<c<':':]or s[~int(c)]
print s

Try it online!

APL (Dyalog Classic), 25 23 bytes
-2 bytes thanks to @FrownyFrog

((⊂⌷⊢)⍣≡⍳∘≢-11|⎕d∘⍳)⊃¨⊂

Try it online!
uses ⎕io←1
(⍵ below stands for an intermediate value in the evaluation)
⎕d is the string '0123456789'
⎕d⍳⍵ finds the (1-based in this case) indices of ⍵'s chars in ⎕d; for a non-digit the index is 11
11|⍵ is modulo - the 11s become 0s
≢⍵ is the length of ⍵
⍳≢⍵ is 1 2 ... till ≢⍵
so, (⍳≢⍵)-11|⎕d⍳⍵ gives us a vector i of the indices where we should look to get the resulting characters; however some of those indices may redirect to yet other (smaller) indices. To compute the transitive closure (i.e. the effective indices), we index the vector into itself (⊂⌷⊢, a train equivalent to (⊂i)⌷i or i[i]) and repeat that until it stabilises (⍣≡ is known as the fixed point operator).
finally we index into the original string: (...)⊃¨⊂

How would it look as a train?

@FrownyFrog indeed, shorter

PHP 7.1 67 59 bytes
while(_&$c=$argn[$i++])$t.=($c^"0")<"
"?$t[~+$c]:$c;echo$t;

Takes input from STDIN; run as pipe with -nR or try it online.

_&$c=$s[$i++] loop through string (_&$c will result in something that is not "0"; so the only character that can break the loop is the empty string = end of input)
$c^"0" toggle bits 5 and 6 in the ascii code
<"\n" check if result is < chr(10)
if so, it is a digit: print previous character by index (and copy to current index)
else print this character

Thanks @Christoph for saving 12%

I know this is an old answer but: Negative string offsets ! (and that $s=$argn ... ?) for(;_&$c=$argn[$i++];)$t.=($c^"0")<"\n"?$t[~+$c]:$c;echo$t;

Vim macro/keystrokes, 49 29 bytes
^M represent the return character (0x0A, 1 byte).
qaqqa/\d^Myl@=@"+1^Mhylnvp@aq@a

Explanation
qaq                                 clear register a
   qa                               record into a
     /\d^M                          move the cursor to the next digit
          yl                        yank the digit
            @=@"+1^Mh               move the cursor left that number of characters plus one
                     yl             yank the char
                       n            go back to the digit
                        vp          replace the digit with the yanked char
                          @a        recursive call will execute until the search for a digit fails
                            q       stop recording
                             @a     run the macro

Python 2,83 80 bytes
r=input()
for i in r:
 if'/'<i<':':r=r.replace(i,r[r.find(i)+~int(i)],1)
print r

Try it online!

saved 3 bytes but checking ascii instead of is digit! Thanks to math_junkie!

Japt, 24 bytes
£Xn >J?U=UhYUgJ+Y-X):PÃU

Try it online!
Explanation:
£Xn >J?U=UhYUgJ+Y-X):PÃU
£                     Ã    Iterate through the input (implicit U)
                             X becomes the iterative item, Y becomes the index
 Xn                          Try parseInt(X)
    >J                       > -1
                               In this case, this checks if X is a digit
      ?                      If true:
       U=                      Set U to
         UhY                     U with the char at index Y set to:
            UgJ+Y-X               The index at -1+Y-X
                   ):        Else:
                     P         variable P (just a no-op in this case)
                       U   Finally, return U

Ruby, 56 46 bytes
->s{i=0;s[i]=s[i+~s[i].to_i]while i=s=~/\d/;s}

Try it online!

Python 2, 58 bytes
lambda s:reduce(lambda t,c:t+(c+t)['/'<c<':'and~int(c)],s)

This is essentially a port of my Jelly answer, plus the digit check from @xnor's Python answer.
Try it online!

Röda, 51 bytes
f a{x=0;a|{|y|a[x]=a[x+47-ord(y)]if[y=~`\d`];x++}_}

Try it online!

JavaScript ES6, 54 bytes
f=r=>[...r].reduce((a,s,i)=>a+(/\d/.test(s)?a[i+~s]:s))

f=r=>[...r].reduce((a,s,i)=>a+(/\d/.test(s)?a[i+~s]:s))

console.log(f("Prog2am0in6"));
console.log(f("abcd"));
console.log(f("a000"));
console.log(f("ban111"));
console.log(f("Hel0o W2r5d!"));
console.log(f("this 222a19e52"));
console.log(f("golfin5 3s24o0d4f3r3y3u"));
console.log(f("Prog2am0in6 Puz0les7&1Cod74G4lf"));
console.log(f("Replicants 4re3lik448ny3oth8r5mac6in8.8T64y'r371it9376a1b5n1fit7or2a1h2z17d."));

Welcome to PPCG! If you don't need your function name for recursive calls, unnamed functions are valid, so you can save two bytes on the f=.

><> (Fish), 108 bytes (= 9 x 12 grid)
01-r>:0(\
"/"&::;?/
)?\v    \
":/v!?(":
")\ :>:"0
 !?\
${/  \ -1
&>\ ~{:&$
\ \ :"0"=
/\- 1}$/?
:v&//}~/~
 \o}\&$/

Try it here to see the fish swimming around.

Append -1 to the input stack then reverse the stack.
Loop: If top value is -1 then end (we've cycled through all characters). Otherwise:
Put the top character in the register; check to see whether it's in the range "0" to "9". If so:

rotate the stack the appropriate number of places
get the character being pointed to
rotate back and replace the number with the character from the register

Output; resume loop.

8086 machine code, 35 bytes
00000000  be 82 00 ac 98 50 2c 30  3c 09 77 0c 4e 89 f7 4e  |.....P,0<.w.N..N|
00000010  29 c6 58 ac aa 89 fe 50  5a b4 02 cd 21 80 fa 0d  |).X....PZ...!...|
00000020  75 e1 c3                                          |u..|
00000023

oK, 39 bytes
{x{x[y 0]:x@-/y}/(!#x),'0|{x*11>x}x-47}

Try it online!

C# (.NET Core), 138 bytes
string d(string x){var e=x.ToCharArray();for(int i=0;++i<e.Length;){if(char.IsDigit(e[i]))e[i]=e[i-((e[i]-'0')+1)];}return new string(e);}

Try it online!

J, 20 bytes
{~[:{~^:_#\-2+_1".,.

Try it online
                  ,.  Each character on a separate row
              _1".    Convert to numbers, replacing non-numbers with -1
                         (it becomes one row again)
            2+        Add 2.
         #\           Prefix lengths (range 1..length)
           -          Subtract
  [:{~^:_             Index into itself as long as it changes the result
{~                    Index into the original string

Credit to ngn for the inspiration.
22 bytes
(],,{~1{._1-_1".[)/@|.

This is a port of the Jelly answer.
                    |. The string backwards, because reduce is right-to-left.
            _1".[      The next character as a number (d), -1 if it's not a number,
                          and a space character produces an empty array.
         _1-           -1-d
      1{.              Take 1. If we have a nothing
                          at this point, that makes it a 0.
   ,                   Prepend the next character to the result of the previous call.
    {~                 Select the character. 0 is the first, _2 is second to last.
 ],                    Append the result.

In both solutions the version that TIO uses interprets a single . as the number 0, so the last test fails. Older versions (≤7) seem to work correctly.
Try it online!

Japt v2.0a0, 16 bytes
r\d@=hYUgY-°X¹gY

Try it

Explanation
                     :Implicit input of string U
r                    :Replace
 \d                  :  RegEx /\d/g
   @                 :  Pass each match X at index Y through a function
     hY              :    Set the character at index Y in U
       UgY-°X        :    To the character at index Y-++X
    =        ¹       :    Reassign to U
              gY     :    Get the character at index Y

PHP, 79 Bytes
for(;++$i<strlen($a=&$argn);)is_numeric($l=$a[$i])?$a[$i]=$a[$i-$l-1]:0;echo$a;

PowerShell, 98 82  76 71 bytes
switch -r(($n=($args|% t*y))){\d{$n[$j]=$n[$j-$_+47]}.{$j++}};$n-join''

Try it online!
Suggestions welcome!
EDIT It looks like powershell will redefine $i when I set it on the right side of the equation in the if statement. I did not realize it looked at that first - saved 1 byte
EDIT 2 Found another way to find the current index by using $j as an index that iterates for each foreach pass - saved 15 bytes and copied method from @AdmBorkBork for creating character arrays [found here][2]! - saved another 6 bytes
EDIT 3 Changed to a switch statement and collapsed unnecessary spaces in the output

REXX, 118 bytes
a=arg(1)
do n=1 to length(a)
  c=substr(a,n,1)
  if datatype(c)=num then do
    a=overlay(substr(a,n-1-c,1),a,n)
    end
  end
say a

Currently 4 JavaScript solutions
x=>[...x].map((p,i,a)=>a[i]=1+p>9?a[i-1-p]:p).join``
r=>[...r].reduce((a,s,i)=>a+(1+s>9?a[i+~s]:s))
s=>s.replace(a=/\d/g,(c,i)=>a[i]=a[i+=~c]||s[i])
x=>f=x!=(x=x.replace(/\d/,(m,o)=>x[o+~m]))?f():x

R, 105 bytes
function(S,s=el(strsplit(S,"")))for(k in 1:nchar(S))cat(s[k]<-"if"(s[k]%in%0:9,s[k-strtoi(s[k])-1],s[k]))

Try it online!

Lua, 111 bytes
s=...z=s:gmatch("()%d")c=z()g=s.sub while c do v=c-g(s,c,c)-1 s=g(s,1,c-1)..g(s,v,v)..g(s,c+1)c=z()end print(s)

Try it online!

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Embedded Hexagons!
Your task: given an integer n, generate an embedded hexagon pattern following the below rules, to the nth depth.
An embedded hexagon has the basic shape of this: (n=0)
 __
/  \
\__/

Embedded Hexagons n=1 and n=2:
  ____
 /  \ \
/\__/  \
\      /
 \____/

    ________
   /  \ \   \
  /\__/  \   \
 /\      /    \
/  \____/      \
\              /
 \            /
  \          /
   \________/

The length of each side is 2 times the length of the same side in the previous depth times two. The top and bottom sides are 2 characters long when n=0 and the rest start out as 1 character long. The non top-bottom side lengths should be 2^n long (OEIS: A000079) and the top and bottom sides should follow the rule 2^(n+1) (same OEIS).
The current hexagons are 0-indexed, you may chose to use 1-indexed if you want.
This is code-golf, so the shortest answer wins!

It might be hard to handle big input (ex. 64). Is there a limit to n?

@SIGSEGV There is no limit to n.

Would be amused to see an answer in Hexagony :))

Heh, the turtle graphics of my Koch curve submission can do this too (only first function changed). Definitely too long for this, though :)

@ØrjanJohansen A long answer is better than no answer!

I really like this challenge but am too tired to have a go now and I guess there will be some much better answers than I could make by the time I get a chance to have a go. Much fun to all who try :)

Charcoal, 40 29 bytes
11 bytes saved thanks to @Neil by changing the while loop to a for-loop amongst other tricks
ＦＮ«ＡＸ²ιβ×__β↓↘β←↙β↑←×__β↖β→↗β

Try it online!
Explanation (outdated)
This program starts with generating the largest hexagon, and then does the smaller ones one-by-one in a while loop (1-indexed). For reference, α is the input number, β is the variable that contains 2^(α-1) and ι is the iterating variable in the loop.
Ｎα                        # Take input and store in α
Ｗα«                       # While α do:
 ×_Ｘ²ι                    #  Write "_"*(2**ι); this forms the top edge of the hexagon
 ↓                         #  Go down
 ＡＸ²⁻ι¹β                 #  Assign 2**(ι-1) to β
 ↘β←                       #  Write \ β times in a SE direction (top right edge) and then go left
 ↙β↑                       #  Write / β times in a SW direction (bottom right edge) and then go up
 ←×_Ｘ²ι                   #  Write the bottom edge
 ↖β→↗β                    #  Just like before, write the top and bottom left edges
 Ａ⁻α¹α                    #  Decrement α
                          # Now the pointer is at the top left corner of the hexagon,
                          # from where the other smaller hexagons will soon be generated

I noticed there's no "Hello, World!" program for Charcoal yet. You should add it.

@mbomb007 Wouldn't that just be a duplicate of the trivial "this language prints its source file if it contains no commands" answer?

I saved some bytes when I realised that ×_Ｘ²ι is the same as ×__β, and some more bytes by converting your Ｗ into a Ｆ, which also avoids having to store the input number. Try it online!.

@Neil Thanks, that is pretty neat :)

Haskell, 230 217 207 bytes
EDIT:

-13 bytes: @xnor saw that my # could be just max.
-10 bytes: And also that zipWith and p could be merged into a ? operator, and that I'd (somehow!) reimplemented replicate.

m takes an Integer and returns a String.
m n=unlines.foldr1 o$((2^n)&).(2^)<$>[0..n]
l&t|a<-c[l,2*t]" _",b<-[c[l-i,1,2*t+2*i-2,1,l-i]" / \\ "|i<-[1..t]]=a:b++r(r<$>o[a]b)
c=(concat.).z replicate
o=max?' '?""
f?e=z f.(++repeat e)
r=reverse
z=zipWith

Try it online!
How it works

m is the main function. It uses & to generate the hexagons with proper padding, then folds them together with o.
l&t generates a small hexagon of side length t, padded inside a large one of side length l, as a list of String lines.

a is the top line of the hexagon, with the underscores.
b is a list of the other lines in the upper half of the hexagon. The lines of b are centered in the padding, which is rectangular; this allows the next step to work.
The bottom half of the hexagon is a overlaid on top of b with o, then reversed (both order of lines and within each line).

c takes two arguments, a list of lengths and a string, and generates a string that has as many copies of each character in the original as the corresponding length, e.g. c[1,3,2]"abc" == "abbbcc". It is used in & to generate the lines.
o takes two arguments representing pictures as lists of lines, and overlays the first, smaller one on top of the second one.

It is used both to combine hexagons and to add the bottom to each hexagon.
It essentially works by using ? twice to pad the first picture with infinitely many spaces both downwards and rightwards, then zipping together corresponding characters with max, which selects the non-space character if there is one.

(f?e)l m pads a list l by appending infinitely many 'e' elements, then zips the resulting list and the list m with the f function.

Nice solution! I think (#) can be max.

The zipping can be combined with p to save bytes: o=max?' '?"";f?e=z f.(++repeat e). Might be shorter pointfree.

(\n->(<$[1..n])) is replicate.

@xnor replicate? Now that's just embarassing. I'm just too used to <$[1..n] or [1..n]>> nearly always winning. However, I don't see how to shorten ? further. I already tried making p pointfree and the ++ is just in the wrong spot, blowing up things with flip.

JavaScript (ES6), 258 bytes

f=(n,s=` `.repeat(1<<n),p=(n?f(n-1):`

`).replace(/(.*)\n/g,s+`$1 `+s)+s,t=`_`.repeat(2<<n))=>(s+t+s+`
`+s.replace(/ /g,"$'/$'$'  $`$`$`$`\\$'\n")).replace(/ /g,(c,i)=>p[i+(1<<n>>1)])+s.replace(/ /g,"$`\\$`$`  $'$'$'$'/$`\n").replace(/ +\/( *)\n$/,t+`/$1
`)
<input type=number min=0 oninput=o.textContent=f(+this.value)><pre id=o>

Explanation: For hexagons after the first, the previous hexagon is first generated and padded on each side (this relies on the output being a rectangle). (For the first heading, some dummy padding is created.) The top and top sides of the hexagon are generated, and all the spaces merged with the previous hexagon. (There's some trickery in order to get the hexagons to line up; this would be easier if extra margins were allowed.) The bottom sides of the hexagon are generated analogously to the top sides, and the bottom of the hexagon is then filled in. Care has to be taken to return rectangular output, including a trailing newline, for the recursion to work.

So, you're demonstrating that this, the Teflon one, and the Deep Dish Pizza one, are all really similar construction? That's kinda neat.

@AdmBorkBork I have a few other answers that do that; those diagonal /s are popular in ASCII art and the replace method is a relatively cheap way of generating them in JavaScript.

1<<n>>1: Nice symmetry ;-)

@Luke I could change the variable to, say, v but sadly the 1 isn't symmetric in any of my usual fonts.

PHP, 337 Bytes
0 Indexing
$h=array_fill(0,1+2*$v=2**($c=$argn),str_pad("",4*$v));for(;1+$c;$c--)for($i=0;$i<$e=2**$c*2+1;$i++){$z=$e-$i<2;$y=$i&&$i<$e/2;$x=$i>=$e/2&$i<$e-1;$h[$i]=substr_replace($h[$i],$s=str_pad(!$y?$z|$x?"\\":"":"/",$e-1+$z-$y+$y*$i*2-$x+$x*2*($e-$i),$z|!$i?"_":" ").(!$y?$z|$x?"/":"":"\\"),$v-$z-$y*$i-$x*($e-$i),strlen($s));}echo join("\n",$h);

Try it online!
Expanded
$h=array_fill(0,1+2*$v=2**($c=$argn),str_pad("",4*$v)); # fill array with maximal width
for(;1+$c;$c--)  # greatest hexagon to lowest
for($i=0;$i<$e=2**$c*2+1;$i++){ # loop through the rows
    $z=$e-$i<2;$y=$i&&$i<$e/2;$x=$i>=$e/2&$i<$e-1; # booleans last first ad second half
    $h[$i]=substr_replace($h[$i], # replace substring
    $s=str_pad(
        $z?"\\":($y?"/":($x?"\\":"")),
        $e-1+$z-$y+$y*$i*2-$x+$x*2*($e-$i),
        $z|!$i?"_":" "
        ).(!$z?!$y?$x?"/":"":"\\":"/"), # with string for smaller hexagon
    $v-$z-$y*$i-$x*($e-$i), # at offset
    strlen($s));
}
echo join("\n",$h); # Output

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Let's do some “enciph5r47g”
This is the inverse of Let's do some "deciph4r4ng"

In this challenge, your task is to encipher a string. Luckily, the algorithm is pretty simple: reading from left to right, each typical writing character (ASCII range 32-126) must be replaced by a number N (0-9) to indicate that it is the same as the character N+1 positions before it. The exception is when the character does not appear within the previous 10 positions in the original string. In that case, you should simply print the character again.
Effectively, you should be able to reverse the operation from the original challenge.
Example
The input string "Programming" would be encoded this way:

Hence, the expected output is "Prog2am0in6".
Clarifications and rules

The input string will contain ASCII characters in the range 32 - 126 exclusively. You can assume that it will never be empty.
The original string is guaranteed not to contain any digit.
Once a character has been encoded, it may in turn be referenced by a subsequent digit. For instance, "alpaca" should be encoded as "alp2c1".
References will never wrap around the string: only previous characters can be referenced.
You can write either a full program or a function, which either prints or outputs the result.
This is code golf, so the shortest answer in bytes wins.
Standard loopholes are forbidden.

Test cases
Input : abcd
Output: abcd

Input : aaaa
Output: a000

Input : banana
Output: ban111

Input : Hello World!
Output: Hel0o W2r5d!

Input : this is a test
Output: this 222a19e52

Input : golfing is good for you
Output: golfin5 3s24o0d4f3r3y3u

Input : Programming Puzzles & Code Golf
Output: Prog2am0in6 Puz0les7&1Cod74G4lf

Input : Replicants are like any other machine. They're either a benefit or a hazard.
Output: Replicants 4re3lik448ny3oth8r5mac6in8.8T64y'r371it9376a1b5n1fit7or2a1h2z17d.

I see that your test cases always use the lowest digit possible for any substitution. Is this required behavior, or can we use higher digits too, when there's more than one possibility?

@Leo You can use any single digit you want 0-9 so long as it's valid.

This is like a move-to-front encoder, except without the moving :)

05AB1E, 20 19 18 bytes
-2 Thanks to Emigna
õ¹vDyåiDykëy}?yìT£

Try it online!
õ                  # Push an empty string
 ¹v y              # For each character in input
   D               # Duplicate the string on the stack (call this S)
     åi            # If this character is in S
       Dyk         #   Push the index of that that character
          ë }      # Else
           y       #   Push the character
             ?     # Print without newline
              yì   # Prepend this character to S
                T£ # Remove all but the first 10 elements from S

I think )¹vDyåiDykëy}?y¸ìT£ works as well.

Actually, combining your answer with mine gives õIvDyåiDykëy}?yìT£ for 18 :)

@Emigna Feel free to update yours with that :)

I wouldn't have thought of it if not for your answer, so you should have it. Good job!

@Emigna I guess that's fair. Thanks!

Got rid of the else statement, but still the same bytecount... Dvy®yåi®sk}?y¸ìT£© may help others who are trying to refactor as well.

Retina, 24 23 bytes
(.)(?<=\1(.{0,9}).)
$.2

Try it online!
A fairly simple regex substitution. We match each character and try to find a copy of it 0-9 characters before it. If we find it, we replace the character with the number of characters we had to match to get to the copy.
The results don't quite match the test cases, because this one uses the largest possible digit instead of the smallest possible one.

Variable length look-behind is cheating :p

@Dada Variable-length lookbehind is the way of enlightenment.

Sadly it is... If you're bored, feel free to implement them inside Perl!

As per OP's comment on the original task, "You can use any single digit you want 0-9 so long as it's valid."... so largest possible should be valid

@DoktorJ yes, I changed it after the OP added that clarification.

JavaScript (ES6), 74 57 54 bytes
Saved 3 bytes thanks to ETHproductions with the brilliant p=/./g instead of p={} (inspired by Neil)
s=>s.replace(p=/./g,(c,i)=>(i=p[c]-(p[c]=i))>-11?~i:c)

Test cases

let f =

s=>s.replace(p=/./g,(c,i)=>(i=p[c]-(p[c]=i))>-11?~i:c)

console.log(f("abcd"));
console.log(f("aaaa"));
console.log(f("banana"));
console.log(f("Hello World!"));
console.log(f("this is a test"));
console.log(f("golfing is good for you"));
console.log(f("Programming Puzzles & Code Golf"));
console.log(f("Replicants are like any other machine. They're either a benefit or a hazard."));

As the string is guaranteed not to contain a digit, can you use s instead of p?

(I was able to outgolf your original find version by using lastIndexOf, which is slightly surprising given that it's 11 letters long....)

@Neil I'm not in front of a computer right now but I don't think that would work since JS strings are immutable.

I can confirm that setting properties on string literals doesn't work. But... it looks like it does work with regex, so I think you could possibly do s=>s.replace(p=/./g,(c,i)=>(i=p[c]-(p[c]=i))>-10?~i:c) to save 3 bytes.

Ah yes, that would only work with a String rather than a string. But I'm glad to see it inspired @ETHproductions!

@ETHproductions Wow ... nice one!

output is something like abcd aaaa banana Hello World! this is a test golfing is g10od 12or you ... in my browser.

chrome 59 dev on osx. - https://i.stack.imgur.com/8vitN.png

@YOU I don't really know what happened here, but it turns out that I introduced a bug for all browsers on my last edit. This is now fixed. Thanks for noticing!

Looks good now. Thank you.

Haskell, 72 66 bytes
Thanks to Laikoni for golfing 6 bytes!
(a:r)%s=last(a:[n|(n,b)<-zip['0'..'9']s,b==a]):r%(a:s)
e%s=e
(%"")

Try it online!
The function % keeps the partially processed string in reverse in its second argument, so it's able to search the first 10 elements of this string for occurences of the character it's examinating. The submission consists of the unnamed function (%"") which calls the previous function with the empty string as its second argument.

f(a:s)=f s++(last$[a]:[show n|(n,b)<-zip[0..9]s,b==a]) saves two bytes.

Wait, f(a:s)=f s++[last$a:[n|(n,b)<-zip['0'..'9']s,b==a]] saves even more.

Reversing on the go instead of using reverse saves one further byte: Try it online!

@Laikoni Thank you, that's wonderful!

Python 2, 64 bytes
s=''
for c in input():d=s[:~10:-1].find(c);s+=-d*c or`d`
print s

Try it online!

What's the point of using ~10 cant you just use -11?

Perl 5, 36 bytes
35 bytes of code + -p flag.
s/(\D)(.{0,9})\K\1/length$2/e&&redo

Try it online!
Some explanations:
The goal is to replace a non-digit character (\D but it correspond to the backreference \1 in my regex) that is preceded by less than 10 characters (.{0,9}) and the same character ((\D)...\1) by the length of the .{0,9} group (length$2). And redo while characters get replaced.

apparently the .* isn't required, any valid char in the range before the replaced digit is ok.

@ConnorLSW Yup, I just saw that update of the challenge and modified my answer, thanks for pointing it out.

Python 2, 89 84 bytes
m=input()[::-1];j=1;t=''
for i in m:s=m[j:].find(i);t=[i,`s`][0<s<10]+t;j+=1
print t

Try it Online!
Iterates throught the string in reverse, and builds a new string with the correct numbers inserted.

Japt, 18 bytes
£¯Y w bX s r"..+"X

Try it online!
Explanation
£   ¯  Y w bX s r"..+"X
mXY{s0,Y w bX s r"..+"X}
                          // Implicit: U = input string
mXY{                   }  // Replace each char X and index Y in U by this function:
    s0,Y                  //   Take U.slice(0,Y), the part of U before this char.
         w bX             //   Reverse, and find the first index of X in the result.
                          //   This gives how far back this char last appeared, -1 if never.
              s           //   Convert the result to a string.
                r"..+"X   //   Replace all matches of /..+/ in the result with X.
                          //   If the index is -1 or greater than 9, this will revert to X.
                          // Implicit: output result of last expression

Python 3, 125 118 bytes
def p(x):print(x,end='')
l={}
for i,c in enumerate(input()):
 if l.get(c,i+9)<i+9:
  p(i-l[c]-1)
 else:
  p(c)
 l[c]=i

Try it online!

JavaScript, 100 80 bytes
x=>x.split``.map((c,b,a)=>{for(i=0;i++<=9&&a[b-i]!=c;);return i>9?c:i-1}).join``

Try it online!

05AB1E, 20 bytes
õIv¹N£RT£©yåi®ykëy}J

Try it online!
Explanation
õ                     # push an empty string
 Iv                   # for each [index,char] [N,y] in input
   ¹N£                # push the first N characters of input
      R               # reverse
       T£             # take the first 10 characters of this string
         ©            # save a copy in register
          yåi         # if y is in this string
             ®yk      #   push the index of y in the string in register
                ë     # else
                 y    #   push y
                  }   # end if
                   J  # join stack as one string

C (tcc), 113 bytes
Since the function creates a copy of an input string, the maximum size of input is 98 characters (more than enough to fit the longest test input). Of course, this can be changed to any other value.
i,j;f(char*s){char n[99];strcpy(n,s);for(i=1;s[i];i++)for(j=i-1;j>-1&&i-j<11;j--)if(n[i]==n[j])s[i]=47+i-j;j=-1;}

Try it online!
Edit
-15 bytes. Thanks Johan du Toit.

Agh! Limit the input to 98 character and save yourself a byte!

Nice solution but you can save another 15 bytes:
i,j;f(char*s){char n[99];strcpy(n,s);for(i=1;s[i];i++)for(j=i-1;j>-1&&i-j<11;j--)if(n[i]==n[j])s[i]=47+i-j,j=-1;}

@JohanduToit Thanks! I have one question. How exactly does s[i] work as a condition of the for loop? I've seen it a lot of times in other people's answers on this website.

@Max Lawnboy. You originally had the following: ‘s[i]^'\0'’ which shorthand for ‘s[i] != '\0'’. The ‘\0’ character literal is equal to zero so you can write it like this: ‘s[i] != 0’. The if statement in C only tests if the value evaluates to zero or non-zero so the ‘!=0’ is not necessary.

100 bytes

Java 7, 102 101 bytes
void a(char[]a){for(int b=a.length,c;--b>0;)for(c=b;c-->0&c+11>b;)if(a[c]==a[b])a[b]=(char)(b-c+47);}

Try it online!
-1 byte thanks to Kevin Cruijssen. I always enjoy an excuse to use the goes-to operator.

Why the --c>=0? You can replace it with c-->0 to save a byte.

@KevinCruijssen I somehow had it in my head that I needed to predecrement otherwise the actual computation would be wrong... Nice catch!

MATL, 31 30 bytes
&=R"X@@f-t10<)l_)t?qV}xGX@)]&h

Try it at MATL Online!
Explanation
        % Implicitly grab input as a string
&=      % Perform element-wise comparison with automatic broadcasting.
R       % Take the upper-triangular part of the matrix and set everything else to zero
"       % For each column in this matrix
X@      % Push the index of the row to the stack
@f      % Find the indices of the 1's in the row. The indices are always sorted in
        % increasing order
-       % Subtract the index of the row. This result in an array that is [..., 0] where
        % there is always a 0 because each letter is equal to itself and then the ...
        % indicates the index distances to the same letters
t10<)   % Discard the index differences that are > 9
l_)     % Grab the next to last index which is going to be the smallest value. If the index
        % array only contains [0], then modular indexing will grab that zero
t?      % See if this is non-zero...
  qV    % Subtract 1 and convert to a string
}       % If there were no previous matching values
  x     % Delete the item from the stack
  GX@)  % Push the current character
]       % End of if statement
&h      % Horizontally concatenate the entire stack
        % Implicit end of for loop and implicit display

You might be a bit off but I super cannot tell where. The input this is a test yields this 222a1te52 instead of this 222a19e52. The second t is not converted to 9.

@EngineerToast Haha thanks. I'll take a look.

PHP, 104 Bytes
forward solution
for($i=0;$i<strlen($a=&$argn);$f[$l]=$i++)$a[$i]=is_int($f[$l=$a[$i]])&($c=$i-$f[$l]-1)<10?$c:$l;echo$a;

Backwards solutions
Online Versions
PHP, 111 Bytes
for(;++$i<$l=strlen($a=&$argn);)!is_int($t=strrpos($argn,$a[-$i],-$i-1))?:($p=$l-$i-$t-1)>9?:$a[-$i]=$p;echo$a;

PHP, 112 Bytes
for(;++$i<$l=strlen($a=&$argn);)if(false!==$t=strrpos($argn,$a[-$i],-$i-1))($p=$l-$i-$t-1)>9?:$a[-$i]=$p;echo$a;

Online Version

REXX, 124 125 bytes
a=arg(1)
b=a
do n=1 to length(a)
  m=n-1
  c=substr(a,n,1)
  s=lastpos(c,left(a,m))
  if s>0&m-s<=9 then b=overlay(m-s,b,n)
  end
say b

You might be a bit off. I don't know REXX but I presume the error is in line 7 where it has s<9 instead of s<10 or s<=9. The input this is a test yields this 222a1te52 instead of this 222a19e52. The second t is not converted to 9. Try it online

Thank you, it was a stupid attempt to shave off one byte. The code has been fixed.

C (gcc), 117 103 93 bytes
i,j;f(char*s){for(i=strlen(s)-1;s[--i];)for(j=i-1;s[j]&&i-j--<10;)if(s[i]==s[j])s[i]=47+i-j;}

Try it online!
No string.h import, works w/ warning. If this is against the rules, I'll pull it.
Pretty Code:
i,j;
f(char *s) {
    // Chomp backwards down the string
    for(i=strlen(s)-1; s[--i];)
        // for every char, try to match the previous 10
        for(j=i-1; s[j] && i-j-- < 10;)
            // If there's a match, encode it ('0' + (i-j))
            if (s[i] == s[j])
                s[i] = 47+i-j;
}

Edits:

Changed from LLVM to gcc to allow implicit i,j declaration, removed lib import.
Added function wrapper for compliance
Decrement in loop boundaries thanks to ceilingcat
Removed break and braces from loop, first match modifies `s[i]

Suggest s[i]==s[j]?s[i]=47+i-j:0 instead of if(s[i]==s[j])s[i]=47+i-j


text:
f(g(x)) decreases while g(f(x)) increases
For this challenge you need to implement two functions, f and g, on the integers, such that f ∘ g is a strictly decreasing function while g ∘ f is a strictly increasing function. In other words, if you take any two integers a < b, then f(g(a)) > f(g(b)) and g(f(a)) < g(f(b)). There are no restrictions on f and g individually, except that they must each map one integer to another integer.
Please include a short description of f and g and an argument for why they have the required property.
Credit: This challenge was inspired by a problem in the 2011 Romanian Master of Mathematics competition (which asks the same thing but on the real numbers, instead of integers). If you really want spoilers, you now know what to search for.
Rules

The word "function" in this challenge should be taken in the mathematical sense of mapping one integer to another: you may either write two programs or two functions and use any of the standard methods of receiving input and providing output, as usual. You may use string representations of integers instead of actual integer variables, but the types of input and output should be identical, so that the functions can be composed without manually converting types in between. Remember that conceptually, f and g still need to be functions on ℤ, so you can't cheat by using two different string representations of the same number or anything like that.

Remember that functions may be unnamed, as long as their name isn't needed by itself or another function you define. If you do name one or both of the functions, you may assume that they exist in the same program, so that they may refer to each other in their implementation (e.g def f(x): return -g(x) in Python).

The usual integer overflow rules apply: your solution must be able to work for arbitrarily large integers in a hypothetical (or perhaps real) version of your language in which all integers are unbounded by default, but if your program fails in practice due to the implementation not supporting integers that large, that doesn't invalidate the solution.

You may use any programming language, but note that these loopholes are forbidden by default.

This is code-golf, so your score is the sum of the number of bytes of both functions and the shortest valid answer wins.

May the functions return a string?

@SIGSEGV I'd say yes, but only if they also take a string as input, so they can be composed without having to insert any type conversion.

Aww darnit, I tried conversion to string to make the other function unable to edit the results further.

I deleted my answer. you say There are no restrictions on f and g individually, except that they must each map one integer to another integer. Therefore if both map integers to lists and lists to integers this is not valid right?

@Fatalize Correct. Each must be a function of type ℤ → ℤ.

Can the functions be piecewise functions?

@AnthonyPham If you mean you may use conditionals in their definitions, then yes of course. Any computable functions on the integers are allowed.

Does it have to work with both negative and positive integers, or can it work with only positive?

@Bijan both positive and negative.

Python, 68 characters
f=lambda x:(1-x%2*2)*(2*x*x+(x<0))
g=lambda x:(1-x%2*2)*(2*x*x+(x>0))

f maps negative numbers to odd numbers and positive numbers to even numbers, and even numbers to positive numbers and odd numbers to negative numbers, with the output magnitude increasing strictly with the input magnitude.
g does the same, except it maps negative numbers to even numbers and positive numbers to odd numbers.
f ∘ g maps negative → even → positive and positive → odd → negative.
g ∘ f maps negative → odd → negative and positive → even → positive.
Therefore f and g have the desired properties.

f and g can be unnamed functions, so you can drop four bytes.

You can define (1-x%2*2) as a variable to save a few bytes.

Here's a complete code to play with `import numpy as np;
import matplotlib.pyplot as plt;
xrange=np.arange(-3,4);
f=lambda x:(1-x%22)(2xx+(x<0));
g=lambda x:(1-x%22)(2xx+(x>0));
plt.plot(xrange, map(f, xrange), 'ro');
plt.plot(xrange, map(g, xrange), 'go');
plt.plot(xrange, map(f, map(g, xrange)), 'b--');
plt.plot(xrange, map(g, map(f, xrange)), 'y--');
plt.show(); You can replace;` with linefeeds for readability.

CJam (17 bytes)
Function f (named F because CJam only allows upper-case names):
{W1$2b,#*}:F

Function g (anonymous):
{F2*}

Online demo
This saves a byte by relying on a implementation detail of CJam which is arguably a bug: when doing base conversions it uses absolute value. 2b, therefore gives the number of bits in the absolute value of its argument, so f negates precisely those numbers whose absolute value has an odd number of bits. g applies f and then doubles (changing the parity of the number of bits).
So applying f and then g leaves sign unchanged and doubles, mapping x to 2x. Applying g and then f changes the sign exactly once and doubles, mapping x to -2x.

Nice, this is exactly the reference solution provided in the competition this is from. (I assume you came up with it independently?)

@MartinEnder, I've seen this problem somewhere before. Possibly on math.SE.

Python, 40 bytes
f=lambda x:x*(-1)**x
g=lambda x:3*f(x)+1

Try it online! Some outputs are floats that equal integers because (-1)**(-3) gives a float for instance.
Based off ideas from Peter Taylor.  The function f negates odd numbers and leaves even ones unchanged. The function g does the same, then applies the monotonic parity-switching map x -> 3*x + 1.
Since f(f(x)) = x, we have g(f(x)) = 3*f(f(x))+1 = 3*x+1 increasing.
For f(g(x)) = f(3*f(x)+1), the idea is that exactly one of the inner and outer f flips sign, making it decreasing.

For even x, f(x) = x, but f(3*x+1) = -3*x-1 because 3*x+1 is odd.
For odd x, f(x) = -x, and f(-3*x+1) = -3*x+1 because -3*x+1 is even.

We now only need the even and odd inputs interleave in a decreasing way, which holds because -3*x±1 is decreasing regardless of how the signs are chosen. This is why the 3* is needed.
A Haskell port is 25 bytes:
f x=x*(-1)**x
g x=1+3*f x

Try it online!

In Haskell, (^) is integer exponentiation.

@user1502040 It can't handle negative exponents.

Since you're not calling g yourself you can save two bytes by making it unnamed.

Pyth, 34 Bytes
This is just a direct translation of my Python answer.
*-1*2%Q2+*2*QQ<Q0
*-1*2%Q2+*2*QQ>Q0