text:
Substring Chainification
Introduction
For this example, let's take the string Hello, World! and the array [3, 2, 3]. To find the substring chain, we go through the following process:
The first number of the array is 3, so we get the substring [0 - 3], which is Hel. After that, we remove the first 3 characters from the initial string, which leaves us with lo, World!.
The second number of the array is 2, so we get the substring [0 - 2] from our new string, which gives us lo. The leftover string becomes , World!.
The last number is a 3, which gives us , W. The substring chain is all of the substrings combined, which gives us:
['Hel', 'lo', ', W']

For a more visual example:
[3, 2, 3], 'Hello, World!'
3 -> Hel
2 ->    lo
3 ->      , W

The task
Given a non-empty string and a non-empty array only consisting of positive integers (> 0), output the substring chain. You may assume that the sum of all integers in the array does not exceed the length of the string.
You can also assume that the strings will never contain any newlines.
Test cases
Input: abcdefghijk, [2, 1, 3]
Output: ['ab', 'c', 'def']

Input: Code Golf, [4, 1]
Output: ['Code', ' ']

Input: Ayyy, [3]
Output: ['Ayy']

Input: lexicographically, [2, 2, 2, 7, 4]
Output: ['le', 'xi', 'co', 'graphic', 'ally']

This is code-golf, so the submission with the smallest number of bytes wins!

05AB1E, 1 byte
£

This is the substring(0,N) command.
Applied on a list this works repeatedly on the remainder on the string.
Try it online!

Can't beat that.

Python 2, 42 bytes
s,a=input()
for n in a:print s[:n];s=s[n:]

Sometimes you just do it the boring way.

So far the shortest of the far-too-many python answers

Well apparently I was overthinking it, haha...

Brachylog, 20 13 bytes
h@[~c.:la~t?,

Try it online!
This is extremely inefficient and times out on TIO for the last test case.
Explanation
Input = [String, List of integers]

h@[            Take a prefix of the string
   ~c.         Take a possible list of strings which when concatenated results in that prefix
      :la      Take the lengths of each element of that list
         ~t?,  This list of lengths is equal to the list of integers of the Input

A slightly more efficient version, 15 bytes
t:{~l}a.,?h@[~c

Python 3, 45 bytes
f=lambda s,a:f(s[a[0]:print(s[:a.pop(0)])],a)

This prints one substring per line and terminates with an error when a is exhausted.
Test it on repl.it.

What a great way to sneak in a print!

Python, 52, 46 bytes
f=lambda a,s:a and[s[:a[0]]]+f(a[1:],s[a[0]:])

A recursive lambda function.
Thanks to Dennis for shaving off 6 bytes!

Jelly, 6 bytes
Jx$ĠịY

Try it online!
        The implicit working value is the first argument.
Jx$     Given a list L, repeat (x) an element of [1..len(n)] (J)
        as many times as the corresponding value in L.
   Ġ    Group indices by values. This turns [1, 1, 1, 2, 2, 3, 3]
        into [[1, 2, 3], [4, 5], [6, 7]].
    ị   Index into the second argument.
     Y  Join by newlines.

Haskell, 34 bytes
s#(a:b)=take a s:drop a s#b
_#_=[]

Usage example: "lexicographically" # [2,2,2,7,4] -> ["le","xi","co","graphic","ally"]
Simple recursion.
Or the boring 29 bytes solution via built-in:
import Data.Lists
splitPlaces

Ruby, 26 bytes
->w,a{a.map{|n|w.shift n}}

Strings are represented as arrays of characters.

PowerShell v2+, 46 bytes
param($a,$b)$b|%{-join$a[$i..($i+=$_-1)];$i++}

Takes input string $a and array $b, loops over $b. Each iteration, does an array slice of $a based on $i (defaults to $null, or 0) and the current number. Needs to do the -1 and $i++ because strings in PowerShell are zero-indexed.
Examples
(The output here is space-separated, because that's the default stringification method for arrays)
PS C:\Tools\Scripts\golfing> @('abcdefghijk',@(2,1,3)),@('Code Golf',@(4,1)),@('Ayyy',@(3)),@('lexicographically',@(2,2,2,7,4))|%{""+$_[0]+" -> "+(.\substring-chainification.ps1 $_[0] $_[1])}
abcdefghijk -> ab c def
Code Golf -> Code
Ayyy -> Ayy
lexicographically -> le xi co graphic ally

Perl, 28 bytes
Includes +1 for -n
Run with the input string on STDIN followed by each number on a separate line:
(echo "Hello, World!"; echo 3; echo 2; echo 3) | perl -nE 'say for/(??{"."x<>||"^"})/g'

Just the code:
say for/(??{"."x<>||"^"})/g

The 23 bytes version without ||"^" also sort of works, but prints spurious trailing newlines
"^" can be replaced by $_ if the string does not contain regex meta characters

JavaScript (ES6), 39 38 35 bytes
Saved 3 bytes thanks to ETHproductions:
s=>a=>a.map(v=>s.slice(t,t+=v),t=0)

Example:
//Definition
f=
s=>a=>a.map(v=>s.slice(t,t+=v),t=0)

//Call
f('lexicographically')([2, 2, 2, 7, 4]);

//Output
Array [ "le", "xi", "co", "graphic", "ally" ]

Previous solution:
38 bytes thanks to Huntro:
s=>a=>a.map(v=>s.substr(t,v,t+=v),t=0)

39 bytes:
(s,a)=>a.map(v=>s.substr(t,v,t+=v),t=0)

You can save one byte by currying

.slice saves a few bytes: s=>a=>a.map(v=>s.slice(t,t+=v),t=0)

MATL, 8 bytes
ys:)1bY{

Try it online!
Explanation
y    % Implicitly take the two inputs: numerical array, string. Duplicate the array
s    % Sum of the array, say n
:    % Range from 1 to n
)    % Take first n characters of the string
1    % Push 1
b    % Bubble up the original copy of the string to the top
Y{   % Split into pieces of lengths given by the numerical array. The pieces are
     % stored in a cell array, which is implicitly displayed, one cell per line

Batch, 74 bytes
@set/ps=
@for %%i in (%*)do @call echo %%s:~0,%%i%%&call set s=%%s:~%%i%%

I'm beating C? This can't be right! Takes the string on STDIN and the array as command-line arguments.

Java, 119 Bytes
String[] substringChainification(String s, int[] i) {
    String[] r = new String[i.length];
    int j = 0, f = 0;
    for (int t : i)
        r[j++] = s.substring(f, f += t);
    return r;
}

Golfed:
String[]s(String s,int[]i){String[]r=new String[i.length];int j=0,f=0;for(int t:i)r[j++]=s.substring(f,f+=t);return r;}

I modified Roman Gräf's answer(https://codegolf.stackexchange.com/a/93992/59935), but i don't have enough rep to comment.
I changed the loop implementation and instead of setting the source string to another substring in every iteration, i just change the indices with which i get the substring.

Welcome to PPCG! Great first post! This is exactly what you should do with a golf suggestion, but not enough rep.

Welcome to PPCG! And I agree with EasterlyIrk, great first post. I tried to find something to golf more, but couldn't. Maybe you've already seen it, but you might find Tips for golfing in Java interesting to read. Once again welcome, and enjoy your stay.

Pyke, 10 bytes
FQR<
Ki?>Q

Try it here!

sed (82 + 2 for -rn) 84
s,^,\n,;:l;N;s,\n\n,\n,;:
s,^([^\n]*)\n(.)([^\n]*\n)1,\1\2\n\3,
t;P;s,^[^\n]*,,;tl

The first line of input is the string. Then each line after that is the size of a substring in unary.
Example:
$ cat test.txt:
lexicographically
11
11
11
1111111
1111

$ cat hold | sed -rnf sed.txt
le
xi
co
graphic
ally

CJam, 11 bytes
lq~{/(ns}/;

Try it online!
Explanation
l    e# Read input string.
q~   e# Read array of lengths and eval.
{    e# For each length...
  /  e#   Split the string into chunks of the given size.
  (  e#   Pull off the first chunk.
  n  e#   Print with linefeed.
  s  e#   Flatten the remaining chunks into a single string again.
}/
;    e# Discard any remainder of the input string.

C, 81 bytes
i,j;f(s,l,k)char*s;int*l;{for(i=j=0;i<k;){write(1,s+j,l[i]);puts("");j+=l[i++];}}

Because write() output is not buffered any online compiler will have a hard time outputting this.
test.c:
i,j;f(s,l,k)char*s;int*l;{for(i=j=0;i<k;){write(1,s+j,l[i]);puts("");j+=l[i++];}}
main(){
    int l[]={3,2,3};
    f("Hello, World!",l,3);
    int ll[]={2,1,3};
    f("abcdefghijk",ll,3);
    int lll[]={4,1};
    f("Code Golf",lll,2);
    int llll[]={3};
    f("Ayyy",llll,1);
    int lllll[]={2,2,2,7,4};
    f("lexicographically",lllll,5);
}

Output without piping:
Hel
lo
, W
ab
c
def
Code

Ayy
le
xi
co
graphic
ally

in ideone compiler l'output of above c program [coping the first function the more hight in the screen] is "Hello, WabcdefCode Ayylexicographically" without "\n"...

PHP, 98 Bytes
<?php
$b=$argv[1];foreach(explode(',',$argv[2])as$a){echo(substr($b,0,$a).' ');$b=substr($b,$a);}

Usage:

php chainification.php lexicographically 2,2,2,7,4

Output:

le xi co graphic ally

There's probably a better solution with PHP.

PHP, 82 Bytes
<?php for($s=$argv[++$i],$j=-1;$n=$argv[++$i];){for(;$n--;)echo$s[++$j];echo"
";}

Takes input as a string and then a list of numbers, output is separated by new lines. e.g.
php chainify.php lexicographically 2 2 2 7 4

If you're one of those people able to use $argv with -r you can save the 6 bytes used for the opening tag.

I am confused about the use of $argv[++$i]. Why not $argv[1] and $argv[2]?

Also, using PHP 7.0.2 at http://sandbox.onlinephpfunctions.com/ I hit the 3 second time limit

it's not $argv[2] because we need to iterate through the supiled arguments and it's $argv[++$i] the first time to avoid the need for a ,$i=1 and thus saving 2 bytes.

PHP, 63 Bytes
<?foreach($_GET[a]as$p){echo" ".substr($_GET[s],$s,$p);$s+=$p;}

Output as Array 85 Bytes
<?foreach($_GET["a"]as$p){$o[]=substr($_GET["s"],$s,$p);$s+=$p;}echo json_encode($o);

Rebol, 38 bytes
func[s b][map-each n b[take/part s n]]

Octave / MATLAB, 31 bytes
@(s,a)mat2cell(s(1:sum(a)),1,a)

This is an anonymous function with inputs s: string; a: numerical array.
Try it at Ideone.
Explanation
This is a port of my MATL answer.
s(1:sum(a))        % Take first n characters of string s, where n is the sum of array a
mat2cell(...,1,a)  % Split into pieces of lengths given by a and store in a cell array

Pyth, 7 bytes
PcwsM._

Takes input separated by newline, with the string unescaped and coming after the array.
Try it Online!
Explanation:
     ._  Get all prefixes of Q
   sM    Map sum across each of these prefixes (to get the total indices)
 cw      Split the string at these locations
P        Remove the last "remainder" of the string

Java 142 bytes
public static String[]substringChain(String s,int[]i){
  String[]r=new String[i.length];
  for(int j=-1;++j<i.length;){
    r[j]=s.substring(0,i[j]);
    s=s.substring(i[j]);
  }
  return b;
}

Golfed:
String[]s(String s,int[]i){String[]r=new String[i.length];for(int j=-1;++j<i.length;){r[j]=s.substring(0,i[j]);s=s.substring(i[j]);}return b;}

Awk, 36 characters
{FIELDWIDTHS=$0;OFS=RS;getline}$1=$1

Sample run:
bash-4.3$ awk '{FIELDWIDTHS=$0;OFS=RS;getline}$1=$1' <<< $'3 2 3\nHello, World!'
Hel
lo
, W

In real life I would use it like this, just no idea how to calculate its score:
bash-4.3$ awk -vFIELDWIDTHS='3 2 3' -vOFS='\n' '$1=$1' <<< 'Hello, World!'
Hel
lo
, W

Dyalog APL 16.0, 15 characters  (non-competing); 15.0, 17 bytes
16.0 solution
{⍵⊆⍨(⍴⍵)↑⍺/+\⍺}

Dyalog APL 16.0 adds APL2's partition primitive, ⊂, with the glyph ⊆.
15.0 solution:
{(-⍺)↑¨(+\⍺)↑¨⊂⍵}

TryAPL online!

Vimscript, 79 78 bytes
not very pretty, I'm sure it can be improved...
Takes a vim buffer, then call echom string(A([2,3])) to see the output
fu A(l)
let r=[]
for i in a:l
exe "norm d".i."l"
let r+=[@"]
endfo
retu r
endf

I actually thought of cheating and outputing the string ["abc", "def"]... But I resisted :P
Explanation: Delete (puts in default register) each array items amounts of characters and adds it to the array r...  A boring answer indeed.

GNU sed, 55 + 2(rn flags) = 57 bytes
1H;1d;G;:;s=.(\n.*)\n(.)=\1\2\n=;t;s=.==;P;s=[^\n]*==;h

Try it online! (thanks to @Dennis for adding sed)
Explanation: The input string should be on the first line and the numbers, in unary, on separate lines after that. A new line is read implicitly at the start of a cycle, running the script each time.
1H;1d                       # once: append string to hold space and start new cycle
                            #Initially, the hold space contains an useful '\n'.
G                           # append hold space to pattern space. The pattern space
                            #format will be: 'UNARY\n\nSTRING'.
:;s=.(\n.*)\n(.)=\1\2\n=;t  # iteratively remove a char from the string, as many
                            #times as unary chars, and store it on 2nd pattern line
s=.==;P                     # remove '\n', then print the new top line
s=[^\n]*==;h                # delete up to '\n' and update hold space

Test run: using a here-document with EOF as the end marker
sed -rnf program.sed << EOF
> abcdefghijk
> 00
> 0
> 000
> EOF

Output:
ab
c
def

Ruby, 28 bytes
->a,w{a.map{|e|w.slice!0,e}}

In case arguments are an array of positive integers and one string.

Common Lisp, 78 76 bytes
Assuming anonymous function is allowed:
(lambda(s l)(loop for x in l as y = x then(+ y x)collect(subseq s(- y x)y)))

Usage
(funcall #'(lambda(s l)(loop for x in l as y = x then(+ y x)collect(subseq s(- y x)y)))"AbCdefGhijK"'(3 2 3))

Output
("AbC" "de" "fGh")

-2 bytes by using as instead of and and changing y definition to fit parentheses between two variables in (subseq ...)

C 474 byte
char**f(char*a,int*b){int  i,j;static char *t[99];for(j=0;j<99;++j)t[j]=0;t[0]=a;for(i=0,j=1;j<99&&a[i]&&b[j-1];++i)if(i>=b[j-1]){t[j++]=a+i;i=0;a=t[j-1];}t[j]=a+i;return j>=99?0:t;}void showResult(char**p, int*b){char *v;int i,j;if(p==0) {printf("NULL"); return;}printf("\'%s\' [", p[0]);for(i=0;b[i];++i)printf("%d%s", b[i], b[i+1]?", ":"");printf("]==[");for(i=0;b[i];++i){printf("\'");for(v=p[i]; v<p[i+1];++v)putchar(*v);printf("\'%s", b[i+1]?", ": "");}printf("]\n");}

main
main()
{char *test[]={"Hello, World", "abcdefghijk", "Code Golf",
               "Ayyy","lexicographically",0}, **p;
 int  v[80];

 v[0]=3;v[1]=2;v[2]=3;v[3]=0;showResult(f(test[0], v), v);
 v[0]=2;v[1]=1;v[2]=3;v[3]=0;showResult(f(test[1], v), v);
 v[0]=4;v[1]=1;v[2]=0;       showResult(f(test[2], v), v);
 v[0]=3;v[1]=0;              showResult(f(test[3], v), v);
 v[0]=2;v[1]=2;v[2]=2;v[3]=7; v[4]=4; v[5]=0;
                         showResult(f(test[4], v), v);
}
/*
 474
 'Hello, World' [3, 2, 3]==['Hel', 'lo', ', W']
 'abcdefghijk' [2, 1, 3]==['ab', 'c', 'def']
 'Code Golf' [4, 1]==['Code', ' ']
 'Ayyy' [3]==['Ayy']
 'lexicographically' [2, 2, 2, 7, 4]==['le', 'xi', 'co', 'graphic', 'ally']
*/

My only post as a question on write one macro function capable of lambda calculus is cancelled, now they do problems on programs that compile and run ok in C compilers where one not find the compiler to programming language they use...saluti, I hope this not will be now cancelled too.

Java - 143 bytes
String[]s(String u,int[]a){String[]k=new String[a.length];for(int i=0;i<k.length;i++){k[i]=u.substring(0,a[i]);u=u.substring(a[i]);}return k;}

Ungolfed version:
String[] s (String u, int[] a) {
    String[] k = new String[a.length];
    for (int i = 0; i < k.length; i++) {
        k[i] = u.substring(0,a[i]);
        u = u.substring(a[i]);
    }
    return k;
}


text:
Are there any languages especially good at ASCII art?
I was wondering if there are any esoteric or golfing languages which specifically target text output and ASCII art?
For example, 05AB1E at least started by targeting base conversions. Are there any golfing languages targeting text output and text output art?
If so, do they have tip pages here, and are they in common use?
Note: I'm not looking for languages that are able to output ASCII art, but rather ones intentionally designed to be able to complete ascii-art challenges in a relatively short and concise way.

Since you mentioned it, in my experience 05AB1E is very good at ascii art challenges.

I'd like to see a ASCII-art language called "ASC and II shall receive." (Seriously though, if one doesn't already exit, there's quite a bit of potential there.)

I've designed a language called Crayon which is made specifically for creating ASCII art, but unfortunately I haven't had the time to implement it yet.

@ASCII-only and I have been working on an ASCII-art language. It's still in the design phase, but we'd love your (or anyone's) input. Join us in chat if you're interested.

Well here I was thinking my idea was unique... I asked this question because I wanted to write a CharMatrix based language. No one's mentioned one of the features I wanted though, so I might go ahead and do it anyway. All the answers and comments have been great by the way, thanks everybody

@SocraticPhoenix what features do you want?

@MarsUltor I was specifically thinking about reflections, with reflectable characters swapping (\ -> /) ({ -> })

@SocraticPhoenix Yeah, we (DLosc and I) will have that in the language we're creating, we just haven't decided on the command character yet

@SocraticPhoenix I've done all the boxchars, but I'm too lazy to do the brackets, you could help group them into horizontal reflection pairs (as a JSON dictionary e.g. "[": "]", "]": "["), also vertical reflection and 180 degree turn (you may need to put some of them in multiple of the dictionaries

@ASCII-only potentially.... I'm quite busy at the moment, with school, etc. If I get a chance I'll try and do some, but I probably won't be able too

@Dennis https://esolangs.org/wiki/Bubblegum I want to see a short post explaining Bubblegum ;).

You should check out Charcoal also, if I had the knowledge I'd write up an answer about it

Well, as a matter of fact, there is! One such language is one I have been working on for a while called V.
Under the hood, V is just vim, but all of the keystrokes are run automatically, and the contents of the vim buffer are printed to STDOUT when the program is over. This just makes running it more convenient.
Some history on the language. When I started using the vim text editor for code-golf, I discovered that it's actually pretty good at it, but has some annoying features that make it more difficult to compete it. For example, you can set up a "while loop" of sorts by doing
qq<foobar>@qq@q

which will repeat <foobar> until an error happens. This has 7 bytes of boilerplate code. In V, this is shortened to ò<foobar>ò.
Some of the things that make V great for ASCII-art:

It is 2d by nature. One feature is that is has a "cursor" position, where most of the commands do something based on where the cursor is in the text. The other commands move the location of the cursor. For example, x deletes a single character, but Wx moves forward a word and then deletes a character. Since most other languages are not intentionally 2 dimensional, this offers a nice edge when the challenge is about positioning text in 2D space
It is entirely string based. You can use some mathy operations, but these are usually the longer way to achieve things.
It uses regex compression to quickly change text.
All of it's internal memory, which is just a 2d array of characters, is implicitly printed when the program ends. Additionally, all inputs is implicitly added into it's internal memory, which is nice when most of the challenge is about changing the input in a certain way.

So I really enjoy using this language, and if you are looking for a specifically ascii-art language, I highly recommend it. However, I would also give a few disclaimers.

It is very confusing to learn. It's also very powerful, but because it's based on a very popular text editor that is 30 years old, there are lot's of obscure features that could very easily confuse new users.
Even though it is better at handling numbers than vim, it's number support is still not great. Personally, I think this makes it more fun to work in (kind of like using retina for tasks regex was never intended for). :D
It is still a WIP. There are some bugs, and some things I haven't gotten around to adding yet.
It doesn't have very many users. (Current number of users: 1).

If you are interested in learning more, here are some good resources:

A chat room where I would be happy to answer any questions you have, and help explain how it works to you.
A tips thread for golfing in vim, but most of the tips carry over.
A meta post describing V in some more detail.

I recently made a new programming language, called Turtlèd, which operates on a grid of characters with a turtle, which moves around the grid, writes to the grid, and has control flow with the grid. The grid is implicitly printed at the end. By this fact that it does not have to write spaces, and that it can write the text spatially, rather than left to right, up to down, it probably makes it meet the definition given, being good at ascii art.
Currently, there are not any docs, so you probably will not be able to use it, unless you want to read my interpreter, which is probably not something you want to do. I think there may also be bugs in the interpreter, but the spec is not developed enough to say if it is a bug. Turtlèd will probably be finished soon, with docs and all, though

Intro to ASCII-Golfing for 05AB1E (Base Conversion [Simple])
While 05AB1E isn't intended for ASCII-Art directly, I've won 2 challenges with it. The best thing about 05AB1E is that, even with the simple base conversion there's often tricks you can use to extend and even halve your byte-count. Often in ASCII challenges there are repitition tricks you can utilize to only draw half the pattern then flip and concatenate. If it's a four way pattern you can do things like zip and bifurcate to only draw a corner of the pattern. There's plenty of data-structure manipulation techniques to use in conjunction with this simple base compression idea.

Here's a quick crash-course on a base conversion tactic:
In 05AB1E I enumerate all of the characters used in the ASCII-art, for instance:
--===___===--
Would result in:
-
=
_

I then assign them numbers starting with 1 then 0 then 2:
- is 1.
= is 0.
_ is 2.

I replace the characters in the original string with the numbers:
1122200022211

I convert to decimal using the lowest possible base (3):
879412

(How to do this using 05AB1E)
I then convert it to base 214:
Jh]

(How to do this using 05AB1E)
I then wrap it in the following code:
05AB1E, 16 bytes
•Jh]•3B…102…-_=‡

Try it online!
Or try it with intermediate steps displayed.
Final explained:
•Jh]•            # Push the compressed ASCII integer.
     3B          # Convert it to base 3.
       …102      # Push the keys to the conversion.
           …-_=  # Push the values to the conversion.
               ‡ # Transliterate, replace 0, 1 and 2 with the symbols.

Now, with this specific challenge the string is so short it doesn't make sense to do. I'd probably just push half the string and Palindromize for 10 bytes "--===__"û or golf it like Adnan did in the comments using factorial, smart man •Jh]•3B5!…-=_‡. He's also (one of?) the creator (s?) of 05AB1E.

More complex example:
https://codegolf.stackexchange.com/a/106621/59376

Also, maybe try Dennis' kolmogorov-complexity language: Bubblegum; no idea how to use this.

Bubblegum isn't really a good lang for ASCII-art, since it cannot possibly take input (except for the two examples), which is required for most ASCII-art challenges. Cinnamon Gum might be a better option, though I don't know much about it and to my knowledge there aren't docs

Not really important, but you can golf this down to: •Jh]•3B5!…-=_‡

@Adnan "--===__"û for 10 ;).

Paintbrush
Paintbrush is a recreational programming language created by myself, Hyper Neutrino, for the purposes of being good at ASCII-Art. It doesn't compete well with Charcoal in many cases, but it can take input and do a variety of other things. It operates on a 2D grid of characters and is able to manipulate the background character, manipulate what is considered a background character at the time, shift rows and columns, move rows and columns, copy rows, columns, or the entire grid, etc.
Some examples may be found in the GitHub repository.

source: Stack Exchange

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

sort: votes


text:
Jimmy these arrays down
My coworker, Jimmy is kinda new to C/C++. He's also kind of a slow learner. Now, to be fair, his code always compiles, but he has some really sloppy habits. For example, everybody knows that you can define an array like this:
int spam[] = {4, 8, 15, 16, 23, 42};

Everybody that is, except for Jimmy. He is convinced that the only way to make an array is like this:
int spam[6];
spam[0] = 4;
spam[1] = 8;
spam[2] = 15;
spam[3] = 16;
spam[4] = 23;
spam[5] = 42;

I keep fixing this for him in code-review, but he won't learn. So I need you to write a tool that automagically does this for him when he commits¹.
The challenge
I want you to write either a full program or a function that takes in a multiline string as input, and outputs the more compact version of the C array. The input will always follow this format, whitespace included:
identifier_one identifier_two[some_length];
identifier_two[0] = some_number;
identifier_two[1] = some_number;
identifier_two[2] = some_number;
...
identifier_two[some_length - 1] = some_number;

In short, the input will always be valid and well defined C. In more detail:
All of the identifiers will be made up of just letters and underscores. The length will always be at least one, and there will never be any missing or out of bounds indexes. You may also assume that the indexes are in order. For example:
foo bar[3];
bar[0] = 1
bar[2] = 9;

foo bar[1];
bar[0] = 1;
bar[1] = 3;

and
foo bar[3];
bar[2] = 9;
bar[0] = 1
bar[1] = 3

are all invalid inputs, and may cause undefined behavior in your submission. You may also assume that all of the numbers will be valid decimal numbers, negative or positive. The input will not have extraneous spaces. The output should always follow this format, whitespace included:
identifier_one identifier_two[] = {n1, n2, n3, ...};

Here is some sample data:
Input:
spam eggs[10];
eggs[0] = 0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;
eggs[4] = 3;
eggs[5] = 7;
eggs[6] = 888;
eggs[7] = 555;
eggs[8] = 0;
eggs[9] = -2;

Output:
spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};

Input:
char ans[2];
ans[0] = 52;
ans[1] = 50;

Output:
char ans[] = {52, 50};

Input:
blah_blah quux[1];
quux[0] = 105;

Output:
blah_blah quux[] = {105};

You may take your input and output in any reasonable format, such as STDIN/STDOUT, function arguments and return value, reading and writing files etc. Standard loopholes apply. The shortest answer in bytes wins!

¹This is passive-aggressive and a terrible idea. You did not get this idea from me.

My apologies to Jimmy

Related.

@DLosc Ah, that's what Jimmy is using in his pre-commit script!

Of course that Jimmy isn't a code golfer.

This challenge really rustled my Jimmies.

Vim, 43 36 bytes
You don't need to give Jimmy a script, just teach him to use a proper text editor. (literal returns for clarity)
:%s/.*=//|%s/;\n/,/<cr><cr>
3wcf ] = {<esc>
$s};

Nice! In this specific instance, <C-a> is shorter than t], which is a fun little hack. Also, I think you technically need 2 <cr> since it asks for confirmation.

Vim answers to standard [tag:code-golf] challenges should be scored in bytes.

Also, norm df= is shorter than s/.*=//g

Also, 3wC] = {<esc> is shorter than <C-a>di]$s = {<esc>.

"vim ... proper text editor" does not compute

@Geobits Where's your Emacs answer?

@Neil Don't misunderstand me. I dislike both :P

@Geobits Then what do you use? Notepad?

@Neil For code? No, I use a Proper Development Environment™

@Geobits Can your Proper Development Environment™, when applied to a 10-million-line codebase, still keep up with someone who types at 100wpm? If so, which one is it? (This is an entirely serious and non-sarcastic question. This is why I have never used a PDE™ for more than two minutes.)

@zwol I haven't worked on large codebases in many PDEs, but in my experience even Eclipse (I know, I know...) keeps up just fine if you turn off Intellisense. With it on, yeah... no.

CJam, 43 36 bytes
qN/('[/~;"[] = {"@{S/W=W<}%", "*"};"

Online Example
Explanation:
qN/                                     |Read all lines to array
   ('[/~;                               |slice first line left of [
         "[] = {"                       |add formatting to stack
                 @                      |rotate to remaining lines
                  {      }%             |for each line in array
                   S/W=                 |split after last space
                       W<               |remove last character (;)
                           ", "*        |insert ", " to array
                                "};"    |add formatting

A big thanks to Martin Ender for the improvements on my first CJam answer.

JavaScript (ES6), 65 64 63 bytes
s=>`${s.split`[`[0]}[] = {${s.match(/-?\d+(?=;)/g).join`, `}};`

Retina, 30 28 bytes
Byte count assumes ISO 8859-1 encoding.
\d+];¶.+
] = {
;¶.+=
,
;
};

Try it online!
Explanation
We'll use the following input as an example:
spam eggs[4];
eggs[0] = 0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;

Stage 1
\d+];¶.+
] = {

Note that there's a trailing space on the first line.
We start by matching a number following by ]; and a linefeed, and then everything up to the last space on the next line. This match can only be found at the end of the first line (due to the ];). All of this is replaced with ] = {. That is, it transforms our example input to:
spam eggs[] = {0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;

Stage 2
;¶.+=
,

Now we match everything from a ; up to the = on the next line and replace with a ,. This transforms the string to:
spam eggs[] = {0, 4, 8, -3;

Stage 3
;
};

All that's left is fixing the end and we do this by replacing the only remaining ; with };:
spam eggs[] = {0, 4, 8, -3};

Julia, 112 108 105 Bytes
f(s)=string(split(s,'[')[1],"[] = {",join([m[1] for m in [eachmatch(r"= *(-?\d+)",s)...]],", "),"};")

Explanation
string(                                                         # build output string
split(s,'[')[1],                                                # get declaration (e.g. spam eggs)
"[] = {",                                                       # add [] = {
join(                                                           # collect numbers
    [m[1] for m in [eachmatch(r"= *(-?\d+)",s)...]],            # regex out (signed) numbers
    ", "),                                                      # and join comma separated
"};"                                                            # add };
)                                                               # close string(

Saved bytes by replacing collect(eachmatch()) with [eachmatch()...] and with a shorter regex

Hi, welcome to PPCG! This looks like a great first answer. +1 from me. Since the challenge states "You may take your input and output in any reasonable format", you can remove the space after the comma separator in the eachmatch function-call for a less pretty output and -1 byte. I never programmed in Julia myself, but you might find this post interesting to read: Tips for golfing in Julia. Again welcome, and enjoy your stay. :)

thanks very much for your kind words :) PPCG seemed to be fun to look into, so I thought I'll give it a try. Chose Julia for this answer as it wasn't present yet

Using matchall would likely be shorter than splatting eachmatch.

i tried using matchall first, but it doesn'lt let me use regex groups (the part in the parenthesis what I am particularly interested in) as opposed to eachmatch. (or I just couldn't find it in the documentation?)

Lua, 121 Bytes.
function g(s)print(s:gmatch('.-%[')()..'] = {'..s:gsub('.-\n','',1):gsub('.-([%d.-]+);\n?','%1, '):gsub(',%s+$','};'))end

Explained
function g(s)
    print(                              -- Print, Self Explaintry.
        s:gmatch('.-%[')()..'] = {'     -- Find the 'header', match the first line's class and assignment name (everything up to the 'n]') and append that. Then, append ] = {.
                                        -- In the eggs example, this looks like; 'spam eggs[] = {' now
        ..                              -- concatenate...
        s:gsub('.-\n','',1)             -- the input, with the first line removed.
        :gsub('.-([%d.-]+);\n?','%1, ') -- Then that chunk is searched, quite boringly, a number followed by a semicolon, and the entire string is replaced with an array of those,
                                        -- EG, '1, 2, 3, 4, 5, 6, '
        :gsub(',%s+$','};')          -- Replace the final ', ' (if any) with a single '};', finishing our terrifying combination
    )
end

C, 121 bytes
n=2;main(i){for(;putchar(getchar())^91;);for(printf("] = {");~scanf("%*[^=]%*c%d",&i);n=0)printf(", %d"+n,i);puts("};");}

Batch, 160 bytes
@echo off
set/ps=
set s=%s:[=[] = {&rem %
set r=
:l
set t=
set/pt=
if "%t%"=="" echo %r%};&exit/b
set t=%t:* =%
set r=%r%%s%%t:~2,-1%
set s=,
goto l

Note: The line set s=, ends with a space. Takes input on STDIN. That weird line 3 takes the input (e.g. int spam[6]; and changes the [ into [] = {&rem resulting in set s=int spam[] = {&rem 6]; which then gets interpreted as two statements, set s=int spam[] = { and rem 6];, the latter of which is a comment. Then for each line we delete the text up to the first space (because you can't use = in a pattern and the matching is non-greedy) and extract the value.

Python 112 111
Very straightforward to me, please suggest any improvement that comes to mind.
def f(l):
 a,*b=l.split('\n')
 return a[:a.index('[')]+'[] = {'+', '.join(r.split(' = ')[1][:-1]for r in b)+'};'

# TEST

lines = """spam eggs[10];
eggs[0] = 0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;
eggs[4] = 3;
eggs[5] = 7;
eggs[6] = 888;
eggs[7] = 555;
eggs[8] = 0;
eggs[9] = -2;"""
print (f(lines))
assert f(lines) == 'spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};'

At a quick look, I can see that there's an useless whitespace at [:-1] for.

05AB1E, 31 30 28 bytes
žh-|vy#¤¨ˆ\}¨… = ¯ïžuDÀÀ‡';J

Explanation
žh-¨                            # remove numbers and ";" from first input
    |v      }                   # for each of the rest of the inputs
      y#                        # split on spaces
        ¤¨                      # take the last element (number) minus the last char (";")
          ˆ\                    # store in global array and throw the rest of the list away
             … =                # push the string " = "
                 ¯ï             # push global array and convert to int
                   žuDÀÀ‡       # replace square brackets of array with curly ones
                         ';     # push ";"
                           J    # join everything and display

Try it online!
Saved a byte thanks to Adnan

žuDÀÀ instead of „[]„{} saves a byte :).

@Adnan: Right, Good catch!

Perl, 42 + 2 (-0p) = 44 bytes
s%\d+].*%] = {@{[join",",/(-?\d+);/g]}};%s

Needs -p and -0 flags to run. For instance :
perl -0pe 's%\d+].*%] = {@{[join",",/(-?\d+);/g]}};%s' <<< "blah_blah quux[1];
quux[0] = 105;"

Java 7, 159 158 149 154 bytes
String c(String[]a){a[0]=a[0].split("\\d")[0]+"] = {\b";for(String i:a)a[0]+=i.split("= [{]*")[1];return a[0].replace(";",", ").replaceFirst("..$","};");}

Multiple bytes saved thanks to @cliffroot.
Ungolfed & test code:
Try it here.
class M{
  static String c(String[] a){
    a[0] = a[0].split("\\d")[0] + "] = {\b";
    for(String i : a){
      a[0] += i.split("= [{]*")[1];
    }
    return a[0].replace(";", ", ").replaceFirst("..$", "};");
  }

  public static void main(String[] a){
    System.out.println(c(new String[]{ "spam eggs[10];", "eggs[0] = 0;", "eggs[1] = 4;",
      "eggs[2] = 8;", "eggs[3] = -3;", "eggs[4] = 3;", "eggs[5] = 7;", "eggs[6] = 888;",
      "eggs[7] = 555;", "eggs[8] = 0;", "eggs[9] = -2;" }));
    System.out.println(c(new String[]{ "char ans[2]", "ans[0] = 52;", "ans[1] = 50;" }));
    System.out.println(c(new String[]{ "blah_blah quux[1];", "quux[0] = 105;" }));
  }
}

Output:
spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};
char ans[] = {52, 50};
blah_blah quux[] = {105};

few bytes saved String c(String[]a){a[0]=a[0].split("\\d")[0]+"]={ \b";for(String i:a)a[0]+=i.split("=[{]*")[1];return a[0].replace(';',',').replaceFirst(".$","};");}

@cliffroot Thanks! Indeed some nice tricks like re-using the String in the parameter and replacing the last char with "};"); instead of an "")+"};";.

jq, 85 bytes
./"
"|(.[0]|gsub("\\d|;";""))+" = {"+(.[1:]|map([scan("-?\\d+")][-1])|join(", "))+"}"

Try it online!
I can probably remove the map, but not sure how to do it without breaking the thing. Otherwise quite satisfied with the solution.

Sorry... I answer a lot of questions.

lmaooooooooooooo

Jelly, 33 bytes
ỴḊḲ€Ṫ€K⁾;,yṖ“{“};”j
ỴḢḟØDṖ,⁾ =,ÇK

TryItOnline
How?
ỴḊḲ€Ṫ€K⁾;,yṖ“{“};”j - Link 1, parse and reform the values, same input as the Main link
Ỵ                   - split on line feeds
 Ḋ                  - dequeue (remove the first line)
  Ḳ€                - split each on spaces
    Ṫ€              - tail each (get the numbers with trailing ';')
      K             - join on spaces
       ⁾;,          - ";,"
          y         - map (replace ';' with ',')
           Ṗ        - pop (remove the last ',')
            “{“};”  - list of strings ["{","};"]
                  j - join (making "{" + "n0, n1, ,n2, ..." + "};")

ỴḢḟØDṖ,⁾ =,ÇK - Main link, takes one argument, the multiline string
Ỵ             - split on line feeds
 Ḣ            - head (just the first line)
   ØD         - digits yield "0123456789"
  ḟ           - filter out
     Ṗ        - pop (remove the trailing ';')
      ,   ,   - pair
       ⁾ =    - the string " ="
           Ç  - call the previous Link (1)
            K - join on spaces (add the space after the '=')

Down voter - what's wrong with it?

Jelly, 27 bytes
Ỵ©ḢḟØDṖ“ = {”®Ḳ€Ṫ€Ṗ€j⁾, ⁾};

Try it online!
Explanation
Ỵ         Split into lines
 ©Ḣ       Take the first one, store the others in ®
   ḟØD    Remove digits
      Ṗ   Remove trailing ;

“ = {”    Print a literal string

®         Recall the remaining lines
 Ḳ€       Split each into words
   Ṫ€     Keep each last word
     Ṗ€   Remove each trailing ;

j⁾,       Join by “, ”
    ⁾};   Literal “};”

sed 51
1s,\[.*,[] = {,
:
N
s,\n.*= ,,
s/;/, /
$s/, $/};/
t

Java, 106 bytes
String manipulation in Java is hell, as always.
a->a[0].join("",a).replaceAll(";\\w+\\[\\d+\\] = ",", ").replaceAll("\\d+\\], ","] = {").replace(";","};")

This is a pure regex answer. Make a single concatenated String, then perform replaceXxx until it's ok.
Testing and ungolfed:
import java.util.function.Function;

public class Main {

  public static void main(String[] args) {
    Function<String[], String> f = a ->
        String.join("", a)                          // I think this would join. Not sure, though. Golfed into a[0].join because static members are accessible from instances.
            .replaceAll(";\\w+\\[\\d+\\] = ", ", ") // replace with regex
            .replaceAll("\\d+\\], ", "] = {")       // replace with regex
            .replace(";", "};");                    // replace no regex

    String[] spam = {
      "int spam[6];",
      "spam[0] = 4;",
      "spam[1] = 8;",
      "spam[2] = 15;",
      "spam[3] = 16;",
      "spam[4] = 23;",
      "spam[5] = 42;"
    };
    test(f, spam, "int spam[] = {4, 8, 15, 16, 23, 42};");

    String[] eggs = {
      "spam eggs[10];",
      "eggs[0] = 0;",
      "eggs[1] = 4;",
      "eggs[2] = 8;",
      "eggs[3] = -3;",
      "eggs[4] = 3;",
      "eggs[5] = 7;",
      "eggs[6] = 888;",
      "eggs[7] = 555;",
      "eggs[8] = 0;",
      "eggs[9] = -2;"
    };
    test(f, eggs, "spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};");

    String[] ans = {
      "char ans[2];",
      "ans[0] = 52;",
      "ans[1] = 50;"
    };
    test(f, ans, "char ans[] = {52, 50};");

    String[] quux = {
      "blah_blah quux[1];",
      "quux[0] = 105;"
    };
    test(f, quux, "blah_blah quux[] = {105};");

  }

  static void test(Function<String[], String> f, String[] input, String expected) {
    System.out.printf("Result:   %s%nExpected: %s%n", f.apply(input), expected);
  }
}

Pip -r, 32 30 bytes
aRXI.']["] = {"(Z@>g@XI1)Jk'}]

Try it online!
Explanation
The builtin regex for matching integers, XI == `-?\d+`, came in really handy here.
aRXI.']["] = {"(Z@>g@XI1)Jk'}]
                                g is list of lines from stdin; a is first line (-r flag)
aR                              In the first line, replace
  XI.']                         integer followed by closing square bracket, with:
                 @>g             All but the first element in g
                    @XI          Find all (two) integers in each element
                Z                Zip that list of pairs into a pair of lists
               (       1)        and take the second list (the values)
                         Jk      Join on ", "
       [                     ]   Put the above string in a list
        "] = {"                  with this string before it
                           '}    and a curly brace after it
                                (The list is converted to a string when used as a
                                replacement; since there are no list-formatting flags
                                in use, its elements are simply concatenated together)

Vyxal aṪ, 28 bytes
ḣƛ⌈t⌊;‛, j\{p\}+$kd$FṪ` = `„

Try it Online!
ḣ                            # Head extract
 ƛ   ;                       # Foreach line except the first
  ⌈t⌊                        # Split on spaces, get the last, parse an int
      ‛, j\{p\}+             # Join by commas and add {}
                $kd$FṪ       # Remove digits from line 1
                      ` = `„ # Push a ` = ` and prepare the stack for printing

Ruby, 64 bytes
->{gets.split(?[)[0]+"[]={"+$<.map{|s|s.scan /\ -?\d+/}*?,+"};"}

Turns out that whitespace is required after all.

V, 25, 24 bytes
3wC] = {òJd2f $s, òhC};

Try it online!
This contains an unprintable <esc> character, so here is a hexdump:
0000000: 3377 435d 203d 207b 1bf2 4a64 3266 2024  3wC] = {..Jd2f $
0000010: 732c 20f2 6843 7d3b                      s, .hC};

Explanation:
3w                              "Move forward 3 words
  C     <esc>                   "Delete everything until the end of the line, and enter this text:
   ] = {                        "'] = {'
             ò         ò        "Recursively:
              J                 "  Join these two lines (which enters a space)
               d                "  Delete everything until you
                2f              "  (f)ind the (2)nd space
                   $            "  Move to the end of this line
                    s           "  Delete a character, and enter:
                     ,          "  ', '
                                "
                        h       "Move one character to the left
                         C      "Delete everything until the end of the line, and enter this text:
                          };    "'};'

JavaScript, 125 bytes
I know it's longer than others, but I really wanted to use eval. Just for fun.
f=function(s){m=/^(\w+ )(\w+).*?(;.*)/.exec(s)
eval("var "+m[2]+"=new Array()"+m[3]+'alert(m[1]+m[2]+"={"+eval(m[2])+"};")')}

To run, paste the following into here:
s='int spam[6];\
spam[0] = 4;\
spam[1] = 8;\
spam[2] = 15;\
spam[3] = 16;\
spam[4] = 23;\
spam[5] = 42;'
f=function(s){m=/^(\w+ )(\w+).*?(;.*)/.exec(s)
eval("var "+m[2]+"=new Array()"+m[3]+'alert(m[1]+m[2]+"={"+eval(m[2])+"};")')}
f(s)

Haxe, 234 bytes
function R(L:Array<String>){var S=L[0];var W=S.indexOf(" ");var T=S.substr(0,W),M=S.substring(W+1,S.indexOf("["));var r=[for(i in 1...L.length)L[i].substring(L[i].lastIndexOf(" ")+1,L[i].length-1)].join(', ');return'$T $M[] = {$r};';}

Long function names killed this :D
Try the testcases here!

Julia 1.0, 81 bytes
!s=split(s,"[")[1]*"[] = {"*join([s[1] for s=eachmatch(r"(-*\d+);",s)],", ")*"};"

Try it online!

Haskell, 80 bytes
f x=takeWhile(/='[')x++"[] = {"++drop 2([", "++w|w<-words x,w<"="]>>=init)++"};"

Try it online! Haskell is normally not very good at string-process-y challenges but it does OK here.
Explanation
takeWhile(/='[')x extracts the typename and identifier "spam eggs". Then we append "[] = {" ++ drop 2 nums ++ "};", where nums is:
 [", "++w|w<-words x,w<"="]>>=init

The "words" (whitespace-delimited parts) of the input that are lexicographically less than "=" happen to be all the digit-plus-semicolon parts like "0;". This is because '-' < '0'..'9' < '=' < 'a'..'z'.
The list comprehension says that to each such part, we prepend a comma and space:
[", 0;",", 4;",", 8;"]

Then >>=init (concatMap init) concatenates and chops off the semicolons:
", 0, 4, 8"

After which point drop 2 gets rid of the initial comma.

Pyth, 42 bytes 39 bytes
+:++:h.z"\d"k" = {"j", "mecd\ t.z\;k"}; // `ecd\ ` takes last word rather than regex replace

+:++:h.z"\d"k" = {"j", "m:d".* "kt.z\;k"};

Try it online!
Explanation
+:++:h.z"\d"k" = {"j", "m:d".* "kt.z\;k"};
  ++                                         // Join the following strings:
    :h.z"\d"k                                //   input[0] with regex \d replaced for empty string
             " = {"                          //   Literal ` = {`
                   j", "                     //   Join with `, ` the following:
                        m:d".* "kt.z         //      Rest of input, removing everything before the numbers
                                             // Now our string looks like:
                                             //   spam eggs[]; = {0;, 4;, 8;, -3;, 3;, 7;, 888;, 555;, 0;, -2;
 :            [our string]          \;k      // Remove ';'
+                                      "};   // Append "};"

all_licenses: 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/


text:
String Concatenation
The Challenge

Given two strings containing only lowercase letters and no spaces, the result should be the shorter string, followed by an underscore, followed by the longer string with the first instance of a character removed for each character it contains that is in the shorter string.
You can assume the strings will always be different lengths.

Test Cases:
sale
salinewater
Result: sale_inwater (only the first 'a' in salinewater is removed)

jostling
juggle
Result: juggle_ostin (juggle is the shorter string)

juggle
juggler
Result: juggle_r (a 'g' is removed for every 'g' in the shorter string)

Rules

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

What does smaller string mean? Shorter?

What does "remove the first occurrence" mean when the shorter string has duplicate characters?

Four days is very short to pick a winner, I'd suggest at least a couple of week at minimum. Also, in the future I'd suggest first posting to the Sandbox where challenges can be clarified and improved before going live.

smaller string is shorter string......sorry for my bad english

You say input strings will be lowercase. Does that mean they only contain (lowercase) letters? Can input strings contain underscores?

What should the output for juggle juggler be? juggle_r (remove for each character instance) or juggle_gr (remove for each distinct character)?

@Pietu1998 That's a good point. We should put this on hold until clarified

@Pietu1998 it will be juggle_r

@Ajay please add your clarifications to the challenge itself. Comments aren't meant to be permanent and answerers are not expected to read all comments.

@Ajay Could you clarify this in the challenge by making an edit? The more relevant information in the question instead of the comments, the more likely votes to re-open will come up. Also, as suggested by xnor, it's recommended to first post in the Sandbox for proposed challenges to retrieve feedback and perfect your challenge before posting it here. Apart from some details this looks like a great first challenge though, so welcome to PPCG!

Hey MartinEnder and Kevin,                                                                             For sure, I will clarify that in question itself

@Ajay You don't really need the Todo bit.

Can we clean up and remove some of these comments now?

Pyth, 13 bytes
++hAlDQ\_.-HG

Try it online.

JavaScript (ES6), 78 75 69 Bytes

const
     g=(x,y)=>x[y.length]?g(y,x):[...x].map(c=>y=y.replace(c,''))&&x+'_'+y
;

console.log(g.toString().length + 2);   // 69
console.log(g('sale', 'salinewater'))   // sale_inwater
console.log(g('juggle', 'juggler'))     // juggle_r
console.log(g('jostling','juggle'))     // juggle_ostin

Breakdown
x[y.length]?g(y,x):        \\ Make sure that x is the shorter string
[...x]                     \\ Spread string in array of characters
.map(c=>y=y.replace(c,'')) \\ For each character remove its first occurence in y
&&x+'_'+y                  \\ Concat x and changed y

Haskell, 56 55 bytes
import Data.List
x%y|(0<$y)<(0<$x)=y%x|z<-y\\x=x++'_':z

-1 byte thanks to @xnor

You can cut a byte by binding y\\x for the 0<1 otherwise guard.

filter(\notElem`x)yis shorter thany\x` with import

@Damien I think that would remove all occurrences of elements of x, not just the first ones.

Oh, yes you are right.

Java 7, 262 bytes
import java.util.*;String c(String z,String y){int i=0,l=y.length();if(z.length()>l)return c(y,z);List x=new ArrayList();for(;i<l;x.add(y.toCharArray()[i++]));for(Object q:z.toCharArray())x.remove(q);String r="";for(i=0;i<x.size();r+=x.get(i++));return z+"_"+r;}

Can probably be golfed some more by just using arrays without the lists..
Ungolfed & test cases:
Try it here.
import java.util.*;
class M{
  static String c(String z, String y){
    int i = 0,
        l = y.length();
    if(z.length() > l){
      return c(y, z);
    }
    List x = new ArrayList();
    for(; i < l; x.add(y.toCharArray()[i++]));
    for(Object q : z.toCharArray()){
      x.remove(q);
    }
    String r = "";
    for(i = 0; i < (x.size()); r += x.get(i++));
    return z+"_"+r;
  }

  public static void main(String[] a){
    System.out.println(c("sale", "salinewater"));
    System.out.println(c("jostling", "juggle"));
    System.out.println(c("juggle", "juggler"));
  }
}

Output:
sale_inwater
juggle_ostin
juggle_r

Java 8, 156 Bytes
String a(String x,String y){int l=x.length(),m=y.length();String b=l>m?x:y,s=m<l?y:x;for(char c:s.toCharArray()){b=b.replaceFirst(""+c,"");}return s+"_"+b;}

This can probably be golfed some more.
Ungolfed & test cases
interface A {
    static String a(String x,String y){
        int l=x.length(),m=y.length();
        String b=l>m?x:y,s=m<l?y:x;
        for(char c:s.toCharArray()){
            b=b.replaceFirst(""+c,"");
        }
        return s+"_"+b;
    }

    static void main(String[]a) {
        System.out.println(a("sale","salinewater"));
        System.out.println(a("jostling","juggle"));
        System.out.println(a("juggle","juggler"));
    }
}

Ruby, 65 bytes
->a,b{a,b=b,a if a.size>b.size;a.chars.map{|e|b.sub!e,""};a+?_+b}

ungolfed
->a, b{
  a, b = b, a if a.size > b.size
  a.chars.map { |e|
    b.sub! e, ""
  }
  a + ?_ + b
}

61 bytes(in case the argument is an array of strings)
->a{a.sort_by!(&:size);a[0].chars.map{|c|a[1].sub!c,""};a*?_}

Thank you, m-chrzan!

gsub! doesn't work here - you're supposed to remove the first occurance of each letter. Fortunately, sub!, which does exactly that, is a byte shorter.

Also, I think you need to name the lambda in this case, since you do end up calling it. However, doing a,b=b,a if a.size>b.size to exchange the strings is non-recursive, and saves you another byte.

@m-chrzan Oh, I didn't observe carefully the question. Thanks!

61 bytes, input as an array of strings: ->a{a.sort_by!(&:size);a[0].chars.map{|c|a[1].sub!c,""};a*?_}

@m-chrzan Great! I added your answer.

Python 2, 81 72 bytes
a,b=sorted(input(),key=len)
for c in a:b=b.replace(c,"",1)
print a+"_"+b

Try it online

I think you can save 9 bytes by replacing the first two lines with a,b=sorted(input(),key=len)

PHP, 154 Bytes
list($f,$s)=strlen($b=$argv[2])<strlen($a=$argv[1])?[$b,$a]:[$a,$b];foreach(str_split($f)as$x)$s=preg_replace("#(.*?)".$x."(.*)#","$1$2",$s);echo$f."_$s";

Instead of $s=preg_replace("#(.*?)".$x."(.*)#","$1$2",$s); you can also use if($z=strstr($s,$x))$s=strstr($s,$x,1).substr($z,1);

R, 161 bytes
This turned out to be much longer than I expected, albeit, string manipulation is usually tedious in R. I feel that this should easily be golfable by just using another approach.
function(x,y){s=strsplit;if(nchar(x)>nchar(y)){v=y;w=x}else{v=x;w=y};v=s(v,"")[[1]];w=s(w,"")[[1]];j=0;for(i in v){j=j+1;if(i==w[j])w[j]=""};cat(v,"_",w,sep="")}

Ungofled
function(x,y){
    s=strsplit                      # alias for stringsplit
    if(nchar(x)>nchar(y)){v=y;w=x}  # assign v/w for the short/long strings
    else{v=x;w=y}
    v=s(v,"")[[1]]                  # split short string into vector
    w=s(w,"")[[1]]                  # split long string into vector
    j=0
    for(i in v){                    # for each char in short string, check
        j=j+1                       # if is equal to corresponding char in
        if(i==w[j])w[j]=""          # long, replace long with "" if true
    }
    cat(v,"_",w,sep="")             # insert _ and print
}

Scala, 78 bytes
def f(a:String,b:String):String={if(a.size>b.size)f(b,a)else
a+"_"+(b diff a)}

Explanation:
def f(a:String,b:String):String={ //define a method f which has two String parameters and returns a String
                                  //(because it's recursive, scala can't figure out the return type)
  if (a.size > b.size)            //make sure that a is the shorter string
    f(b, a)
  else
    a+"_"+(b diff a)              //`b diff a` removes all elements/chars of a from b
}


text:
Find the largest number that's adjacent to a zero
Challenge:
Take a vector / list of integers as input, and output the largest number that's adjacent to a zero.
Specifications:

As always, optional input and output format
You may assume that there will be at least one zero, and at least one non-zero element.

Test cases:
1 4 3 6 0 3 7 0
7

9 4 9 0 9 0 9 15 -2
9

-4 -6 -2 0 -9
-2

-11 0 0 0 0 0 -12 10
0

0 20
20

Good luck and happy golfing!

You should add a test case like the 4th one, but where the result is negative (there are positive numbers in the list).

I was going to try this in Retina, but then I noticed there are negatives. Retina hates negatives.

Don't let retina dictate what you can and cannot do. Take charge, you're the boss!

Jelly, 8 bytes
ṡ2ẠÐḟS€Ṁ

Try it online!
ṡ2            Overlapping pairs
  ẠÐḟ         Remove pairs without zeroes
     S€       Sum of each pair
       Ṁ      Maximum

MATL, 10 bytes
t~5BZ+g)X>

Try it online! Or verify all test cases.
Explanation
Let's take input [-4 -6 -2 0 -9] as an example.
t     % Input array. Duplicate
      %   STACK: [-4 -6 -2 0 -9],  [-4 -6 -2 0 -9]
~     % Logical negate. Replaces zeros by logical 1, and nonzeros by logical 0
      %   STACK: [-4 -6 -2 0 -9],  [0 0 0 1 0]
5B    % Push logical array [1 0 1] (5 in binary)
      %   STACK: [-4 -6 -2 0 -9], [0 0 0 1 0], [1 0 1]
Z+    % Convolution, maintaining size. Gives nonzero (1 or 2) for neighbours of
      % zeros in the original array, and zero for the rest
      %   STACK: [-4 -6 -2 0 -9], [0 0 1 0 1]
g     % Convert to logical
      %   STACK: [-4 -6 -2 0 -9], [0 0 1 0 1]
)     % Use as index into original array
      %   STACK: [-2 -9]
X>    % Maximum of array.
      %   STACK: -2
      % Implicitly display

x(~~(dec2bin(5)-48)). Who's idea was it to implement that one? Very clever, and useful for logical arrays! :) Nice answer!

@WeeingIfFirst Thanks! I had used dec2bin()-'0' hundreds of times in MATLAB, so I knew that one had to be in MATL :-)

By the way, the fact that you included the content of the stack after every operation is worth an upvote alone. It makes it so much easier to understand (and possibly learn) MATL =)

Convolution Rocks. +1

Haskell, 63 43 bytes
f x=maximum[a+b|(a,b)<-tail>>=zip$x,a*b==0]

Thanks to @MartinEnder for 4 bytes!

I think you can use a*b==0 instead of the ||.

You have to go back to previous version with zip. Here a and be are no longer adjacent

You don't need lambdabot here. This is "regular" Haskell

05AB1E, 9 bytes
ü‚D€P_ÏOZ

Explanation
ü‚         # pair up elements
  D        # duplicate
   €P      # product of each pair (0 if the pair contains a 0)
     _     # logical negate, turns 0 into 1 and everything else to 0
      Ï    # keep only the pairs containing at least 1 zero
       O   # sum the pairs
        Z  # take max

Doesn't work in the online interpreter, but works offline.

This is amazing haha! Just in time :p.

@Adnan: Indeed. Awesome timing :)

Just implemented one of these operators or? :)

@WeeingIfFirst: ü was added just yesterday :)

Won’t this return 0 if the actual answer would be negative? You have to throw out the zeroes, I think.

@Lynn Nice catch! This can easily be fixed by replacing ˜ with O (sum).

@Lynn: Right you are. Thanks for catching that bug :)

Pyth, 12 11 10 bytes
eSsM/#0,Vt

Forms pairs, filters by zero member, sorts by sum, returns largest.

,Vt (implicit QQ) returns the same pairs as .:Q2, but with the pairs flipped. Should work, though.

f}0T is /#0

JavaScript (ES6), 59 57 56 bytes

let f =

l=>l.map((n,i)=>m=l[i-1]==0|l[i+1]==0&&n>m?n:m,m=-1/0)|m

console.log(f([1, 4, 3, 6, 0, 3, 7, 0]));       // 7
console.log(f([9, 4, 9, 0, 9, 0, 9, 15, -2]));  // 9
console.log(f([-4, -6, -2, 0, -9]));            // -2
console.log(f([-11, 0, 0, 0, 0, 0, -12, 10]));  // 0
console.log(f([3, 0, 5]));                      // 5
console.log(f([28, 0, 14, 0]));                 // 28

Edit: saved 2 bytes thanks to Huntro
Edit: saved 1 byte thanks to ETHproductions

You can save two bytes by using == instead of ===

I you can save a few bytes in several places: l=>l.map((n,i)=>m=l[i-1]*l[i+1]==0&n>m?n:m,m=-1/0)|m

Error: {
"message": "Syntax error",
"filename": "http://stacksnippets.net/js",
"lineno": 15,
"colno": 3
}

@RosLuP - This requires ES6 with arrow function support and won't work on all browsers (including, but not limited to: all IE versions before Edge, all Safari versions below v10, etc.)

Python, 49 bytes
lambda a:max(sum(x)for x in zip(a,a[1:])if 0in x)

Tests are at ideone
Zips through the pairs, sums the ones containing any zero, returns the maximum.

JavaScript (ES6), 53 bytes
a=>(m=-1/0,a.reduce((l,r)=>(m=l*r||l+r<m?m:l+r,r)),m)

Because I like using reduce. Alternative solution, also 53 bytes:
a=>Math.max(...a.map((e,i)=>e*a[++i]==0?e+a[i]:-1/0))

PHP, 77 68 71 bytes
-3 bytes from anonymous, -4 and -2 from MartinEnder
preg_match_all("#(?<=\b0 )\S+|\S+(?= 0)#",$argv[1],$m);echo max($m[0]);

run with php -r '<code>' '<space separated values>'

using \K to discard the match so far is shorter than using a look-behind.

You can also use space separation for input and then use \S+ to match a signed integer. You'll probably have to use \b0, so you don't have to prepend the ,.

Does this work for input like 4 0 0 5 ?

@TonHospel No. Does \K not work with alternatives? For unknown reason, the second alternative returns 0 0, so that there is no more 0 to match before the 5. Fixed, thanks.

Make a look at the other PHP solution with register_globals

@JörgHülsermann Take a look at my comment to that.

Ruby, 51 bytes
->a{a.each_cons(2).map{|a,b|a*b!=0?-1.0/0:a+b}.max}

usage
f=->a{a.each_cons(2).map{|a,b|a*b!=0?-1.0/0:a+b}.max}
p f[gets.split.map(&:to_i)]

I don't think you need the parentheses around a+b.

@Martin Ender syntax error occurs... https://ideone.com/F6Ed4B

It works in Ruby 2.3. (available here for instance: https://repl.it/languages/ruby)

@Martin Ender When I use "!=" instead of "==", it works. Thanks for your advice! https://ideone.com/F6Ed4B

There's a bug in there :(. -3 -2 0 returns 0. I think replacing ...?0:... with ...?-1.0/0:... should fix it, adding 5 bytes.

@m-chrzan I didn't notice that. Thanks for information.

Java 7, 118 105 106 bytes
int d(int[]a){int i=0,m=1<<31,c;for(;++i<a.length;m=a[i]*a[i-1]==0&(c=a[i]+a[i-1])>m?c:m);return m;}

13 bytes saved thanks to @cliffroot by using an arithmetic approach instead. 1 additional byte thank to @mrco after he discovered a bug (the added test case 2, 1, 0 would return 2 instead of 1).
Ungolfed & test code:
Try it here.
class M{
  static int c(int[] a){
    int i,
        m = a[i=0],
        c;
    for(; ++i < a.length; m = a[i] * a[i-1] == 0 & (c = a[i] + a[i - 1]) > m)
                           ? c
                           : m);
    return m;
  }

  public static void main(String[] a){
    System.out.println(c(new int[]{ 1, 4, 3, 6, 0, 3, 7, 0 }));
    System.out.println(c(new int[]{ 9, 4, 9, 0, 9, 0, 9, 15, -2 }));
    System.out.println(c(new int[]{ -4, -6, -2, 0, -9 }));
    System.out.println(c(new int[]{ -11, 0, 0, 0, 0, 0, -12, 10 }));
    System.out.println(c(new int[]{ 0, 20 }));
    System.out.println(c(new int[]{ 2, 1, 0 }));
  }
}

Output:
7
9
-2
0
20
1

slightly different approach using arithmetics, seems to be working
int d(int[]a){int i,m=a[i=0],c;for(;++i<a.length;m=a[i]*a[i-1]==0&(c=a[i]+a[i-1])>m?c:m);return m;}

The output is wrong, when the first number is not adjacent to 0, but larger than any number adjacent to 0. Reproducible by the test case {2, 1, 0}.
You can fix this by initializing i with 0 directly and m with 1<<31 (+1 overall).

Jelly, 6 5 bytes
SfµƝṀ

Try it online!
-1 remembering it's not a dyadic chain
  µƝ     For each pair of adjacent elements, monadically:
S        Sum the pair,
 f       and filter it to only element[s] in the pair.
    Ṁ    Take the maximum.

Nekomata, 7 bytes
qᵗZđ+aṀ

Attempt This Online!
qᵗZđ+aṀ
q           Non-deterministically choose a contiguous subsequence
 ᵗZ         Check that it contains a 0
   đ        Unpair; check that its length is 2, and push the two elements
    +       Add
     a      All possible values
      Ṁ     Maximum

CJam, 16 bytes
q~2ew{0&},::+:e>

Try it online! (As a test suite.)
Explanation
q~    e# Read and eval input.
2ew   e# Get all (overlapping) pairs of adjacent values.
{0&}, e# Keep only those that contain a 0.
::+   e# Sum each pair to get the other (usually non-zero) value.
:e>   e# Find the maximum.

MATLAB with Image Processing Toolbox, 32 bytes
@(x)max(x(imdilate(~x,[1 0 1])))

This is an anonymous function. Example use for the test cases:
>> f = @(x)max(x(imdilate(~x,[1 0 1])))
f =
  function_handle with value:
    @(x)max(x(imdilate(~x,[1,0,1])))

>> f([1 4 3 6 0 3 7 0])
ans =
     7

>> f([9 4 9 0 9 0 9 15 -2])
ans =
     9

>> f([-4 -6 -2 0 -9])
ans =
    -2

>> f([-11 0 0 0 0 0 -12 10])
ans =
     0

>> f([0 20])
ans =
    20

Mathematica, 46 43 bytes
Saved 3 bytes due to @MartinEnder.
Max[Tr/@Partition[#,2,1]~Select~MemberQ@0]&

Anonymous function. Takes a list of integers as input and returns an integer as output. Based off of the Ruby solution.

R, 48 47 bytes
EDIT:
Fixed an error thanks to @Vlo and changed it to read input from stdins, saved one byte by assigning w and skipping parantheses.

function(v)sort(v[c(w<-which(v==0)-1,w+1)],T)[1]

v=scan();w=which(v==0);sort(v[c(w-1,w+1)],T)[1]

Unnested explanation

Find indices for which the vector v takes on the values 0: w <- which(v == 0)
Create new vector which contains the indices +-1: w-1 and w+1
Extract elements that match the indices w-1 and w+1
Sort in descending order and extract fist element

Note that if the last or first element of v is a zero, w+-1 will effectively fetch an index outside of the length of the vector which implies that v[length(v)+1] returns NA. This is generally no problem but the max() functions inconveniently returns NA if there are any occurrences in the vector unless one specifies the option na.rm=T. Thus it is 2 bytes shorter to sort and extract first element than to use max(), e.g.:
max(x,na.rm=T)
sort(x,T)[1]

Need an extra parenthesis otherwise fails all test cases where max is to right of 0 such as c(1, 4, 3, 6, 0, 10, 7, 0) c((w<-which(v==0))-1,w+1) Also a tad bit shorter with scan sort((v<-scan())[c(w<-which(v==0)-1,w+1)],T)[1]

@Vlo Thanks for pointing that obvious error out, +1. In your suggested solution you forgot the ()too though ;). Updated the code and assigned v prior manipulation now.

Dyalog APL, 14 bytes
⌈/∊2(+↑⍨0∊,)/⎕

⌈/ largest of
∊ the flattened ("enlisted"
2(...)/ pairwise
 + sum (zero plus something is something)
 ↑⍨ taken if
 0 zero
 ∊ is a member of
 , the pair (lit. the concatenation of the left-hand number and the right-hand number)
TryAPL online!

K (ngn/k), 14 bytes
|/+/'(*/')_2':

Try it online!
|/+/'(*/')_2':
           2':   pairs
     (*/')_      discard those whose product are nonzero
  +/'            sum of each pair
|/               maximum

Julia, 56 55 Bytes
f(l)=max(map(sum,filter(t->0 in t,zip(l,l[2:end])))...)

Create tuples for neighboring values, take those tuples containing 0, sum tuple values and find maximum

Perl, 42 bytes
Includes +1 for -p
Give the numbers on line on STDIN
largest0.pl <<< "8 4 0 0 5 1 2 6 9 0 6"

largest0.pl:
#!/usr/bin/perl -p
($_)=sort{$b-$a}/(?<=\b0 )\S+|\S+(?= 0)/g

J, 18 bytes
[:>./2(0&e.\#+/\)]

Explanation
[:>./2(0&e.\#+/\)]  Input: array A
                 ]  Identity. Get A
     2              The constant 2
      (         )   Operate on 2 (LHS) and A (RHS)
               \    Get each subarray of size 2 from A and
             +/       Reduce it using addition
           \        Get each subarray of size 2 from A and
       0&e.           Test if 0 is a member of it
            #       Filter for the sums where 0 is contained
[:>./               Reduce using max and return

Vyxal G, 36 bitsv2, 4.5 bytes
2lƛ∑w↔

Try it Online!
Porting Jelly is (still) always the best option
Explained
zṠ↔G
z     # Overlapping pairs (equivalent to 2l)
 Ṡ    # summed (vectorised)
  ↔   # with only items in the input kept.
   G  # Get the biggest number in that list.

Created with the help of Luminespire.

Did you forget the update the code, TIO, and byte-count? zṠ↔ is 3.375 bytes, isn't it? Or is it incorrect somehow, and you forgot to roll-back the explanation?

Nibbles, 8.5 bytes
`/.|!$>>@:?$0+$]

Attempt This Online!
Disgustingly long…
`/.|!$>>@:?$0+$]
    !    :       Zip
     $            the input
      >>          with the tail of
        @         the input
   |             Filter by
          ?$0     containing a zero
  .              Map
             +$   sum
`/             ] Maximum

BQN, 14 bytes
⌈´((«∨»)0⊸=)⊸/

Try
Seemed like a good excuse to use the shifts in «∨».

13: ⌈´(«∨»)∘=⟜0⊸/

@Bubbler I was just coming here to post that exact solution!

J, 16 bytes
}.>./@(+#~0=*)}:

Attempt This Online!
}.>./@(+#~0=*)}:
}.            }:    Input without first and without last, respectively
          0=*       elementwise product equals 0?
       +            elementwise sum
        #~          filter the left by the right being true
                    (the right is true iff one of the two is zero,
                    and the corresponding sum is the other number)
  >./@              maximum of those

Vyxal 3 G, 4 bytes
oᶻΠf

Try it Online!
oᶻΠf
o     # overlapping pairs
 ᶻΠ   # where the product is zero
   f  # flatten

Created with the help of Luminespire.

3 byters fail on [4,5,9,1,0,0]

Fails on [9, 4, 9, 0, 19, 1, 9, 15, -2]

@emanresuA luckily there were other 4 byters

Python 2, 74 Bytes
def f(x):x=[9]+x;print max(x[i]for i in range(len(x)) if 0in x[i-1:i+2:2])

Cycle through every element, if there's a 0 in the position of either the left or the right of the current element, include it in the generator, and then run it through max. We need to pad the list with some non-0 number. It'll never be included because the slice [-1:2:2] won't include anything.

C# 76 74 bytes
using System.Linq;i=>i.Zip(i.Skip(1),(a,b)=>a*b==0?1<<31:a+b).Max();

Explanation:
Use zip to join the array with itself but skipping the first value in the 2nd reference so that item zero joins to item one.  Multiply a times b, if the result is zero, one of them must be zero and output a + b.  Otherwise, output the minimum possible integer in the language.  Given the assumption that we will always have a zero and a non-zero, this minimum value will never be output as the max.
Usage:
[TestMethod]
public void LargestFriend()
{
    Assert.AreEqual(7, F(new int[] { 1, 4, 3, 6, 0, 3, 7, 0 }));
    Assert.AreEqual(9, F(new int[] { 9, 4, 9, 0, 9, 0, 9, 15, -2 }));
    Assert.AreEqual(-2, F(new int[] { -4, -6, -2, 0, -9 }));
    Assert.AreEqual(0, F(new int[] { -11, 0, 0, 0, 0, 0, -12, 10 }));
    Assert.AreEqual(20, F(new int[] { 0, 20 }));
}

Hi. you can remove the space at int[]i) {. Also, I count 75 bytes in your current code (74 if you remove the space).

I think you can save 4 bytes by inverting the ternaries: a?b?i.Min()).Max():a:b

Plus using System.Linq;, no?

True but this question just asked for a method, not a full program and using System.Linq; is part of the default new class template.

@Grax Either way you need to include the using statement in your byte count

However compiling to a Func<int[], int> gets you 50 bytes + using System.Linq; for 68 bytes: using System.Linq;i=>i.Zip(i.Skip(1),(a,b)=>a*b==0?1<<31:a+b).Max();

Where do I find the instructions for this format?

T-SQL, 182 bytes
Golfed:
DECLARE @x varchar(max)='1 5 4 3 6 1 3 17 1 -8 0 -7'

DECLARE @a INT, @b INT, @ INT WHILE @x>''SELECT @a=@b,@b=LEFT(@x,z),@x=STUFF(@x,1,z,''),@=IIF(@a=0,IIF(@b<@,@,@b),IIF(@b<>0 or @>@a,@,@a))FROM(SELECT charindex(' ',@x+' ')z)z PRINT @

Ungolfed:
DECLARE @x varchar(max)='1 5 4 3 6 1 3 17 1 -8 0 -7'

DECLARE @a INT, @b INT, @ INT
WHILE @x>''
  SELECT
   @a=@b,
   @b=LEFT(@x,z),
   @x=STUFF(@x,1,z,''),
   @=IIF(@a=0,IIF(@b<@,@,@b),IIF(@b<>0 or @>@a,@,@a))
  FROM(SELECT charindex(' ',@x+' ')z)z
PRINT @

Fiddle

PowerShell v3+, 62 bytes
param($n)($n[(0..$n.count|?{0-in$n[$_-1],$n[$_+1]})]|sort)[-1]

A bit longer than the other answers, but a nifty approach.
Takes input $n. Then loops through the indices 0..$n.count, uses the Where-Object (|?{...}) to pull out those indices where the previous or next item in the array is 0, and feeds those back into array slice $n[...]. We then |sort those elements, and take the biggest [-1].
Examples
PS C:\Tools\Scripts\golfing> @(1,4,3,6,0,3,7,0),@(9,4,9,0,9,0,9,15,-2),@(-4,-6,-2,0,-9),@(-11,0,0,0,0,0,-12,10)|%{""+$_+" --> "+(.\largest-number-beside-a-zero.ps1 $_)}
1 4 3 6 0 3 7 0 --> 7
9 4 9 0 9 0 9 15 -2 --> 9
-4 -6 -2 0 -9 --> -2
-11 0 0 0 0 0 -12 10 --> 0

PS C:\Tools\Scripts\golfing> @(0,20),@(20,0),@(0,7,20),@(7,0,20),@(7,0,6,20),@(20,0,6)|%{""+$_+" --> "+(.\largest-number-beside-a-zero.ps1 $_)}
0 20 --> 20
20 0 --> 20
0 7 20 --> 7
7 0 20 --> 20
7 0 6 20 --> 7
20 0 6 --> 20

q, 38 bytes
{max x where 0 in'x,'(next x),'prev x}

This doesn't seem to work when the maximum comes after a 0. Also, I'm no q expert, but I think you would have to surround your code with {} to make it a function.

Perl 6, 53 bytes
{max map ->$/ {$1 if !$0|!$2},(1,|@_,1).rotor(3=>-2)}

Expanded:
# bare block lambda with implicit signature of (*@_)
{
  max

    map

      -> $/ {           # pointy lambda with parameter ｢$/｣
                        # ( ｢$0｣ is the same as ｢$/[0]｣ )
        $1 if !$0 | !$2 # return the middle value if either of the others is false
      },

      ( 1, |@_, 1 )     # list of inputs, with added non-zero terminals
      .rotor( 3 => -2 ) # grab 3, back-up 2, repeat until less than 3 remain
}

PHP, 66 bytes
foreach($a=$argv as$k=>$v)$v||$m=max($m,$a[$k-1],$a[$k+1]);echo$m;

Pretty straightforward. Iterates over the input, and when a number is 0, it sets $m to the highest number of the 2 adjacent numbers and any previous value of $m.
Run like this (-d added for aesthetics only):
php -d error_reporting=30709 -r 'foreach($a=$argv as$k=>$v)$v||$m=max($m,$a[$k-1],$a[$k+1]);echo$m;' -- -4 -6 -2 0 -9;echo

SPSS Syntax (98 bytes)
Golfed solution:
CRE L=lead(A,1).
COMP R=MAX(lag(A),L).
EXE.
SEL IF A=0.
EXE.
AGG
/S=MAX(R).
LIST S
/CAS=1.

Ungolfed:
CREATE L=lead(A,1).
COMPUTE R=MAX(lag(A),L).
EXECUTE.
SELECT IF A=0.
EXECUTE.
AGGREGATE
/S=MAX(R).
LIST S
/CASES=1.

Explanation:
Input values is ordered vertically in a column.
The first line of code creates a column with the lead number, the number before any given number. MAX(lag,A) returns the lagging number, the number after any given number (in test series A). So the second line of code creates a column with the highest number of neighbourging numbers of any given number. We are only interested in the neighbours of zeros, so the forth line selects all the rows with zeros, which now also include the highest valued neighbours. The 6th and 7th line of code finds the max value of selected neighbours.
With data inputs:
* This syntax solves: Returning the greatest adjacent number bigger or equal to itself,
  for any number V.
* CodeGolf asks for the solution for the case V=0.
* Bytes=98.

DATA LIST LIST
/ Sample (A7) a b c d e f g h i j k l m .
BEGIN DATA.
"A" 1, 4, 3, 6, 0, 3, 7, 0
"B" 9, 4, 9, 0, 9, 0, 9, 15, -2
"C" -4, -6, -2, 0, -9
"D" -11, 0, 0, 0, 0, 0, -12, 10
"E"  0, 20
END DATA.
DATASET NAME Inputs WINDOW=FRONT.

FLIP VARIABLES=a b c d e f g h i
/NEWNAMES=Sample.
DATASET NAME CodeGolf WINDOW=FRONT.
DATASET CLOSE Inputs.

CRE L=lead(A,1).
COMP R=MAX(lag(A),L).
EXE.
SEL IF A=0.
EXE.
AGG
/S=MAX(R).
LIST S
/CAS=1.

Just change the sample references (A to E) for testing each sample.

I'm assuming your indentation is a bit off. Otherwise it's 126 bytes =)

Ok, thanks. Fixed that now.

What is SPSS syntax? Just curious. Also, welcome to PPCG!

@qwerp-derp Thank you for the welcome! :-) SPSS Syntax is a high-level data management programming language within the fourth generation of programming languages . It is used within IBM SPSS Statistics software package for statistical analysis.

R, 48 54 bytes
s=scan()

w=which;max(s[c(w(s==0)+1,w(s==0)-1)],na.rm=T)

Reads vector from console input, then takes the maximum over all values adjacent to 0.
Edit: Catches NAs produced at the boundary, thanks rturnbull!

Am I doing it wrong? http://pastebin.com/0AA11xcw

This fails for cases such as 20 0, because s[w(s==0)+1] returns NA, and max's default treatment of NA is to return it. You can fix by adding the argument na.rm=T, or re-work the code to use sort (see the other R answer posted above).

Can you condense everything into one line? I don't know how to code in R, but I'm assuming you can.

@Qwerp-Derp: Not as far as I know. scan() waits for console input to read in the vector, the input stream is closed by entering an empty line. If you were to run the two lines as one, the second part would be at least partially recognized to be input for to the vector s.

Thunno 2 G, 6 bytes
ḣZæp}ʂ

Try it online!
Explanation
ḣZæp}ʂ  # Implicit input
ḣZ      # All overlapping pairs
  æp}   # Filter by product == 0
     ʂ  # Sum each inner pair
        # Implicit output of maximum

awk

gawk '{__=!_++?+$NF:!NF?(!_<__?__:!_):__<+(!RT||+$NF<+$!_? $!_:\
         $!_=$NF)?+$!_:__ }END{ print __ }' RS='(^| +)0([ \n]+|$)'

-11 0 0 0 0 0 -12 10
0
-4 -6 -2 0 -9
-2
0 20
20
1 4 3 6 0 3 7 0
7
9 4 9 0 9 0 9 15
9

Is it possible in pure bash?

@Simd : any framework that's Turing Complete is always possible, question is ease of adaptability, which I have no idea, but my uneducated guess is that most likely it'd be rather verbose, given how one must space out arguments instead of clumping them like that in awk. The utter lack of typing in awk is a godsend without having to worry about integer-division only in bash, and any caveats when dealing with negatives, like the current question.

a lot of times I see code from those thinking maximizing things done within the shell is an ideal approach "because it doesn't spawn extra PIDs", so they literally go down Alice in the Wonderland kind of rabbit holes trying handle some task that would be very seamless if it routed via awk / sed / python etc, and returning the result back to the shell.

Scala, 106 97 bytes
A port of @Kevin Cruijssen's Java 7 answer in Scala.
Saved 9 bytes thanks to the comment of @ceilingcat

Golfed version. Try it online!
a=>{var(i,m,c)=(0,1<<31,0);while({i+=1;i<a.length})if(a(i)*a(i-1)==0)m=Math.max(a(i)+a(i-1),m);m}

Ungolfed version. Try it online!
object M {
  def c(a: Array[Int]): Int = {
    var i = 0
    var m = 1 << 31
    var c: Int = 0

    while ({i += 1; i < a.length}) {
      if (a(i) * a(i - 1) == 0) {
        c = a(i) + a(i - 1)
        m = Math.max(c, m)
      }
    }
    m
  }

  def main(args: Array[String]): Unit = {
    println(c(Array(1, 4, 3, 6, 0, 3, 7, 0)))
    println(c(Array(9, 4, 9, 0, 9, 0, 9, 15, -2)))
    println(c(Array(-4, -6, -2, 0, -9)))
    println(c(Array(-11, 0, 0, 0, 0, 0, -12, 10)))
    println(c(Array(0, 20)))
    println(c(Array(2, 1, 0)))
  }
}

Pip, 15 bytes
M$|*:0N_FIgZ@>g

Takes the numbers as command-line arguments. Attempt This Online!
Explanation
M$|*:0N_FIgZ@>g
          g      ; List of command-line args
           Z     ; Zip with
            @>g  ; All but the first element of that same list
        FI       ; Filter those pairs of elements on this function:
     0N_         ;   Contains a 0
 $|*:            ; Fold each pair on logical OR
M                ; Maximum

Racket 183 bytes
(λ(k)(let*((lr(λ(l i)(list-ref l i)))(l(append(list 1)k(list 1)))(m(for/list((i(range 1(sub1(length l))))
#:when(or(= 0(lr l(sub1 i)))(= 0(lr l(add1 i)))))(lr l i))))(apply max m)))

Detailed version:
(define f
 (λ(k)
    (let* ((lr (λ(l i)(list-ref l i)))
           (l (append (list 1) k (list 1)))
           (m (for/list ((i (range 1 (sub1(length l))))
                         #:when (or (= 0 (lr l (sub1 i)))
                                    (= 0 (lr l (add1 i))) ))
                (lr l i) )))
      (apply max m) )))

Testing:
(f (list 1 4 3 6 0 3 7 0))
(f (list 9 4 9 0 9 0 9 15 -2))
(f (list -4 -6 -2 0 -9))
(f (list -11 0 0 0 0 0 -12 10))
(f (list 0 20 ))

Output:
7
9
-2
0
20

C 132 bytes
Outputs using main's return code:
int main(int a,char**_){int i,m=0;_[0]=_[a]="1";for(i=1;i<a;++i){m=(*_[i-1]-48||*_[i+1]-48?m>atoi(_[i])?m:atoi(_[i]):m);}return m;}

I feel like I should be able to save a few bytes by saving one of the atoi calls, but I couldn't find an efficient way. (,t plus t= plus , plus t twice is too long). Also this technically uses undefined behaviour (setting _[a] to "1") but every compiler I know of allows it by default.
Strategy: pad the start and end of the array with 1, then loop over the internal section checking each neighbor.

PHP 69 64 bytes
Some bytes on and off from Jörg Hülsermann and Titus. = (-5)
Requires register_globals enabled. Usage: http://localhost/notnull.php?i[]=9&i[]=-5i[]=...
$x=$_GET['i'];
$y=0;
foreach($x as $j){
if($y<abs($j)){
$y=$j;
}
}
echo $y;

Golfed:
$x=$_GET['i'];$y=0;foreach($x as $j)if($y<abs($j))$y=$j;echo $y;

Why do not use directly the input as array. I could not seen the reason for json_encode.

For non-default settings you have to add the full length of the setting change to your byte count. (see http://meta.codegolf.stackexchange.com/q/4778#4778) In this case +21 bytes for -d register_globals=1 (or specify a version where register_globals is enabled by default)

But json_decode is a nice idea.

@Titus What I mean is ?id[]=1&id[]=2&id[]=3  and then $_GET["id"] gives back an array. For this reason json_decode makes no sense for me

@JörgHülsermann It costs bytes, but it´s still a nice idea.

This answer is incorrect

YASEPL, 91 bytes
=1'±" "=l®1=h-99=i`1!o¥i,1}7,0,2!i]4!m$i-=s¥m,1}2,h,2|3`4!m$i+=s¥m,1}2,h,2`3!h$s`2!i+}2,l>h

explained:
=1'±" "=l®1=h-99=i`1!o¥i,1}7,0,2!i]4!m$i-=s¥m,1}2,h,2|3`4!m$i+=s¥m,1}2,h,2`3!h$s`2!i+}2,l>h                   packed
=1'                                                                                set var1 to user input
   ±" "                                                                                split A by every space
       =l®1                                                                                set L to the length of var1
           =h-99                                                                                set H to -99 (atorage for highest number)
                =i                                                                                set I to 0 (incrementer)
                  `1                                                              !i }2,l                     do while I < L ...
                    !o¥i,1}7,0,2                                                `2                               if(var1[i] == 0) ...
                                !i]4!m$i-=s¥m,1}2,h,2|3`4                 `3                                         and if(i != 0 and if(var1[i-1] > h) ...
                                                         !m$i+=s¥m,1}2,h,2                                           or if(var1[i+1] > h) ...
                                                                            !h$s                                        set H to S and continue (found higher number)
                                                                                +                            increment I and loop.
                                                                                >h                   print H once done.

Uiua SBCS, 14 bytes
/↥≡/+▽=0≡/×.◫2

Try it!
/↥≡/+▽=0≡/×.◫2
            ◫2  # overlapping pairs
           .    # duplicate
        ≡/×     # products
     ▽=0        # keep those equal to zero
  ≡/+           # sums
/↥              # max


text:
Telegraphy Golf: Decode Baudot Code

Background
In 1870 Émile Baudot invented Baudot Code, a fixed-length character
encoding for telegraphy. He designed the code to be entered from a
manual keyboard with just five keys; two operated with the left hand and
three with the right:

The right index, middle and ring fingers operate the I, II, and
III keys, respectively, and the left index and middle fingers operate
IV and Ⅴ. (Henceforth I'll use the more familiar numerals 1–5.) Characters are entered as chords. To enter the letter
"C," for example, the operator presses the 1, 3, and 4 keys
simultaneously, whereupon a rotating brush arm reads each key in
sequence and transmits a current or, for keys not depressed, no current.
In modern terms, this is a 5-bit least-significant-bit-first
binary encoding, in which our example, "C," is encoded as 10110.
5 bits??
You might be thinking that 5 bits, which can express at most 32 unique
symbols, isn't enough for even all of the English letters and numerals,
to say nothing of punctuation. Baudot had a trick up his sleeve, though:
His character set is actually two distinct sets: Letters and
Figures, and he defined two special codes to switch between them.
Letter Shift (LS), which switches to Letters mode, is activated by pressing
the 5 key alone (00001), and Figure Shift (FS) is activated with the
4 key (00010).
Challenge
Your challenge is to write a program or function that decodes Baudot
Code transmissions.
A real transmission would begin with some initialization bits, plus a
start and stop bit before and after each character, but we're going to
skip those and only worry about the 5 unique bits for each character.
Input and output formats are discussed below.
Baudot's Code
There are two different versions of Baudot Code: Continental and U.K.
We're going use the U.K. version, which doesn't include characters
like "É" from Baudot's native French. We're also going to leave out all
of the symbols in the U.K. version that aren't among the printable ASCII
characters. You will only have to decode the characters in the table
below, all of which are printable ASCII characters except the final three control characters that are explained below the table.
The "Ltr" column shows the characters in Letter mode and "Fig" shows the
Figure mode characters:
        Encoding             Encoding
Ltr Fig  12345       Ltr Fig  12345
--- --- --------     --- --- --------
 A   1   10000        P   +   11111
 B   8   00110        Q   /   10111
 C   9   10110        R   -   00111
 D   0   11110        S       00101
 E   2   01000        T       10101
 F       01110        U   4   10100
 G   7   01010        V   '   11101
 H       11010        W   ?   01101
 I       01100        X       01001
 J   6   10010        Y   3   00100
 K   (   10011        Z   :   11001
 L   =   11011        -   .   10001
 M   )   01011        ER  ER  00011
 N       01111        FS  SP  00010
 O   5   11100        SP  LS  00001
 /       11000

The last three rows in the right column are control characters:

ER is Erasure. Baudot's telegraphy machines would print an
asterisk-like symbol for this character to tell the reader that the
preceding character should be ignored, but we're going to be even
nicer to the reader and actually omit (do not print) the preceding
character. It acts the same in both Letter and Figure mode.

FS is Figure Shift. This switches the character set from
Letters to Figures. If the decoder is already in Figure mode,
FS is treated as a Space (ergo SP in the "Ltr" column). When the decoder is in Figure mode it stays in Figure mode until an LS character is received.

LS is Letter Shift. It switches the character set from
Figures to Letters. If the decoder is already in Letter mode, LS is treated as a Space. When in Letter mode the decoder stays in Letter mode until an FS character is received.

The decoder always starts in Letter mode.
Here's an example with Figure Shift, Letter Shift, and Space:
01011 10000 00100 00001 00010 10000 11100 00001 10101 11010
  M     A     Y   LS/SP FS/SP   1     5   LS/SP   T     H

This yields the message MAY 15TH. As you can see, the first 00001 (Letter Shift/Space) character acts as a space, because the decoder is already in Letter mode. The next character, 00010 (Figure Shift/Space) switches the decoder to Figure mode to print 15. Then 00001 appears again, but this time it acts as Letter Shift to put the decoder back in Letter mode.
For your convenience, here are the characters in a format that's perhaps
easier to digest in an editor, sorted by code:
A,1,10000|E,2,01000|/,,11000|Y,3,00100|U,4,10100|I,,01100|O,5,11100|FS,SP,00010|J,6,10010|G,7,01010|H,,11010|B,8,00110|C,9,10110|F,,01110|D,0,11110|SP,LS,00001|-,.,10001|X,,01001|Z,:,11001|S,,00101|T,,10101|W,?,01101|V,',11101|ER,ER,00011|K,(,10011|M,),01011|L,=,11011|R,-,00111|Q,/,10111|N,,01111|P,+,11111

Input
Input will be a string, array, or list of bits in
least-significant-bit-first order. Each character will be represented by a quintet of 5 bits. Bits may be in any reasonable format, e.g. a
binary string, an array of 0s and 1s, a string of "0" and "1"
characters, a single very large number, etc., as long as it maps
directly to the bits of the transmission.
Every transmission will have at least one printable quintet and at most
255 quintets (printable or otherwise), i.e. 5–1,275 bits inclusive.
The input can contain only the bits of the transmission, with two
allowed exceptions: Any number of leading or trailing 0 bits and/or,
for string input, a single trailing newline may be added to the
transmission. Leading or trailing bits or characters cannot be added
before or after each quintet, i.e. you cannot pad each quintet to 8 bits (or take each quintet as a single number in an array—unless your language has a 5-bit integer type)
or separate quintets with any additional bits, e.g. "01111\n11100".
Notes & edge cases

The transmission will contain only the characters in the "Ltr" and
"Fig" columns in the table above. You will never receive e.g.
01110 in Figure mode, because it is absent from the "Fig" column.

It is assumed that the decoder will always be in Letter mode at the
beginning of a transmission. However, the first character may be an
FS character to switch to Figure mode immediately.

When the decoder is in Letter mode, it may receive an LS character, and when it is in Figure mode it may receive an FS character. In either event a Space character must be printed (see Output).

The ER character will never be the first character in a transmission, nor will it ever immediately follow an LS, FS, or another ER.

An FS character may immediately follow an LS character and vice versa.

Neither the LS nor FS character will be the last character in any transmission.

The / and - characters may be received in either Letter mode
(codes 11000 and 10001, respectively) or Figure mode (10111
and 00111).

Output
Output may be in any reasonable format, the most reasonable being ASCII
(or UTF-8, for which all of the represented characters are the same as
ASCII). Please indicate in your answer if your output is in another
encoding or format.
Notes

The space character (see 3. above) should be an ASCII space (0x20)
or your encoding's equivalent, i.e. what you get when you press the
space bar.

Winning
This is code-golf. The shortest code in bytes wins.
Restrictions

Standard loopholes are forbidden.

Trailing spaces and/or a single trailing newline are allowed. Leading spaces or other characters (that are not part of the transmission) are disallowed.

You may not use any built-in or library functions that decode Baudot Code (or any of its descendants, e.g. Murray Code, ITA-1, etc.).

Test Cases
Input: 001101000010100111101110010101
Output: BAUDOT

Input: 11010010001001100011110111101111100
Output: HELLO

Input: 01011100000010000001000101000011100000011010111010
Output: MAY 15TH

Input: 0001000100010000001000001011101110011100101010010110101010001111100101
Output: 32 FOOTSTEPS

Input: 10110000110101011100111100001111011010000001101110
Output: GOLF

Input: 000100011000001111100000100010110111001100010110010000111111
Output: 8D =( :P

Input: 0000100001000010000100010001111011111011000011100010001
Output (4 leading spaces):     -/=/-

Related.

Note: I encoded the test cases by hand; if you see anything that looks wrong please speak up.

In the code table and the accompanying digest, code 00010 is listed as SP in letter mode, and FS in figure mode. According to the description, if we're in letter mode and we receive code 00010, we should shift to figure mode, but the values in the table seem to be the other way around. Also, vice versa for 00001.

@Sok You're right, I transposed the Ltr and Fig columns in each of those rows. I've fixed both the table and the digest. Thanks!

This man was pretty damn smart, I never knew about the compression used in telegraphy. Thanks for the history lesson man.

@carusocomputing Right?? Baudot had no formal education beyond primary school, but not only did he invent Baudot Code, he invented a multiplexing system that allowed four operators to use a single telegraph line simultaneously. I found this 1919 pamphlet that describes his inventions in some detail super interesting: http://www.samhallas.co.uk/repository/telegraph/b6_baudot_multiplex.pdf

For erasure, is it permissible to use the backspace character ('\b' aka '\x08'), or must the previous character actually not be printed? The backspace character works on most terminals that I have come across, but it doesn't work on things like TIO.

@Phlarx Sure, I'll allow it.

Is Baudot Code a valid output encoding?

Pyth, 98 97 95 93 90 83 80 bytes
The code contains unprintable characters, so here is a reversible xxd hexdump:
00000000: 753f 7133 4a69 4832 5047 2b47 3f3c 334a  u?q3JiH2PG+G?<3J
00000010: 4040 6332 2e22 275a 75ae 5751 fb4e 3cd7  @@c2."'Zu.WQ.N<.
00000020: 02ce 8719 aac1 e0e0 fe1f 09e5 85bc a767  ...............g
00000030: 8e0c 1f47 508a cad1 1acb b26f 951e e5d6  ...GP......o....
00000040: 225a 4a2a 5c20 715a 3d5a 744a 637a 356b  "ZJ*\ qZ=ZtJcz5k

Try it online. Test suite.
Quite long, but the lookup table does take up most half of the space.
For 117 bytes, here's the same thing without unprintables (needs ISO-8859-1, though):
u?q3JiH2PG+G?<3J@@c2."'Zu®WQûN<×\x02Î\x87\x19ªÁààþ\x1f\tå\x85¼§g\x8e\x0c\x1fGP\x8aÊÑ\x1aË²o\x95\x1eåÖ"ZJ*\ qZ=ZtJcz5k

Or, for 93 bytes, with no compression on the lookup table:
u?q3JiH2PG+G?<3J@@c2"OVDPYSBREXGMIWFNA-JKUTCQ/ZHL5'0+3;8-2;7);?;;1.6(4;9/;:;="ZJ*\ qZ=ZtJcz5k

JavaScript (ES6),  160 158 153  149 bytes
s=>s.replace(m=/.{5}/g,s=>["? !YSBREXGMIWFNA-JKUTCQ/ZHLOVDP? ?!3 8-2 7) ?  1.6(4 9/ : =5'0+"[(n='0b'+s-1)<2?m^n?~(m^=1):1:m<<5|n]]).replace(/.!/g,'')

Try it online!

Chip, 1069 bytes
It's a big'n, but was quite fun to write.
Takes input as a string of "1"'s and "0"'s. (Though it really only looks at the low bit.)
 AZZZZ,-o.AZZZZ  AZZZZ,o-.AZZZZ
*\\\\\]oo[\/\\\**//\\\]oo[/\\\\*
*\\\\/]oo[\/\\/**//\\/]oo[/\\\/*
*\\\//]oo[\/\//**//\//]oo[/\\//*
*\\\/\]oo[\/\/\**//\/\]oo[/\\/\*
*\\//\]oo[\///\**////\]oo[/\//\*
*\\///]oo[\////**/////]oo[/\///*
*\\/\/]oo[\//\/**///\/]oo[/\/\/*
*\\/\\]oo[\//\\**///\\]oo[/\/\\*
=
        o--------K-----o
      ,oo.   z---+~S  ,oo.
     ,LooR. !ZZZZ'   ,LooR.
    ,LLooRR.        ,LLooRR.
   ,LLLooRRR.      ,LLLooRRR.
  ,LLLLooRRRR.    ,LLLLooRRRR.
 ,LLLLLooRRRRR.  ,LLLLLooRRRRR. ,~Z
,LLLLLLooRRRRRR.,LLLLLLooRRRRRR.>m'
|||||||oo||||||||||||||oo||||||)/Rz.
xxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxx\^-^S
x)x))))))))))))xx)))))))))))))xx\g
xx)xxxxxxxxxxxxxxxxxxxxxxxxxxx))\f
xxxxxx))xxxxxxxxxxxxx)))))))))xx\e
xx)x))x)xxxxx))x)))))xxxxxxx)))x\d
xx))x))xxx)))xxxxx)))xxxx)))xx)x\c
xx)xx)xx))x))x)xx)xx)xx))x))x)xx\b
x)))))))x)xx)xxxx)x)xx)x)xx)xx)x\a
x)x)x))))))x)x))x)))x)))xx))x))x/f
x)x)x))))))x)x)xxx)xxxxxxxx)x)xx/e
xxxxxxxx))xxxxxx))))x)))xxx)x))x/d
xxxxx))xxxxx)x)xxx)xxx))xx))xx)x/c
xxx)xxx)xxxx)x)xxxxxx))xxx))x))x/b
x)xxx)x)x)xx)xxxxx))x)))xx))xxxx/a

Try it online!
Note: Erasure uses the ASCII backspace character (\x08), which means that they'll look funny in TIO, but they look fine in, say, xterm.
Basic Structure
At the top, above the = line, is the input decoder. It turns the input into one of 32 separate signals. These are sent from the o's above the = to those below.
The triangular mountains of L's and R's just rotate the pattern from separate rows to columns. The grid below that translates each column to its output character. For unknown signals, NUL (\x00) is produced. For the special shifts, instead of printing a character, the little blob to the right changes the mode.
The cable-car like thing between the two mountains suppresses any printing between each quintet, otherwise, this would attempt to decode all overlapping quintets too. Try replacing the ! with a * to see this for yourself. (Running in verbose mode -v may also be of interest here.)
I'm not sure how to make this smaller at the moment; it's already quite dense for its size.

Batch, 306 304 bytes
@echo off
set/pc=
set r=
set d=! !!YSBREXGMIWFNA-JKUTCQ/ZHLOVDP!! !3!8-2!7)!?!!1.6(4!9/!:!=5'0+
set s=2
:l
set/an=(s^&32)+0%c:~,2%%%6*8+0x%c:~2,3%%%14
set c=%c:~5%
if %n%==%s% set/as^^=35&goto l
call set r=%%r%%%%d:~%n%,1%%
if %r:~-1%==! set r=%r:~,-2%&goto l
if not "%c%"=="" goto l
echo %r%

Takes input on STDIN. Since Batch has no binary conversion, I have to fake it using octal and hex conversion.

The first two digits are converted from octal (I can't use decimal because the first digit might be 0). Possible values are 00, 01, 10 and 11. The latter two have value 8 and 9 but I want 2 or 3 so I take the remainder modulo 6.
The last three digits are converted from hexadecimal. Digits are either 14 or 252 times their desired value, to I take the remainder modulo 14 (252=14*18).
c is the coded string
r is the result so far
d is the decoding array
s is the the index (taking the shift state into account) of the character that switches shift state
n is the binary decode plus bit 5 of s, which either equals the shift state, in which case the shift state is toggled, or indexes into the decoding array to find the next character (or ! to erase)

PHP, 206 Bytes
foreach(str_split($argv[1],5)as$s)($k="# f*YSBREXGMIWFNA-JKUTCQ/ZHLOVDP#l *3#8-2#7)#?##1.6(4#9/#:#=5'0+"[32*$f+bindec($s)])=="*"?array_pop($a):($k=="f"?$f=1:($k=="l"?$f=0:($k=="#"?:$a[]=$k)));echo join($a);

GNU sed, 334 + 1 = 335 bytes
+1 byte for -r flag. Takes input on STDIN.
Looking over old challenges I realized this one would be pretty easy with sed, and good for practice. I haven't attempted any compression, so the lookup table is more than half the code.
s|.*|#@&;01000E211000/%00100Y310100U401100I%11100O500010f 10010J601010G711010H%00110B810110C901110F%00001 l10001-.01001X%11001Z:00101S%10101T%01101W?11101V'00011<<10011K(01011M)11011L=00111R-10111Q/01111N%11111P+10000A111110D0|
:
s/@([01]{5})(.*;.*\1)(..)/\3@\2\3/
t
s/@;.*//
s/#f /@/
s/@ l/#/
s/#(.)./\1#/
s/@.(.)/\1@/
t
s/.<|[#@]//g

Try it online!
Explanation
The code works in two phases: First, it replaces each run of 5 binary digits with the corresponding two characters (letter and figure) from a lookup table. The lookup table is in the format … where  is a binary digit and  and  are the corresponding letter and figure, respectively. % stands in for missing characters (this could be any character other than newline). FS/SP is represented by f<space> and SP/LS is <space>l. ER is represented by <<.
Then it steps through each pair with a "cursor" corresponding to the current mode—# for letter mode, @ for figure mode. The # cursor removes the second character of the pair and then advances to the next pair, and the @ removes the first and advances. In other words, #A1B8 becomes A#B8 and then AB#, and @A1B8 becomes 1@B8 and then 18@. When the # cursor encounters f<space> it deletes it and replaces itself with the @ cursor, and vice versa when @ encounters <space>l.
When no pairs remain, the final cursor is removed along with any characters followed by <.
# Setup: Append a lookup table to the line.
# Also prepends "#" and "@" which we'll use as "cursors" later.
s|.*|#@&;01000E211000/%00100Y310100U401100I%11100O500010f 10010J601010G711010H%00110B810110C901110F%00001 l10001-.01001X%11001Z:00101S%10101T%01101W?11101V'00011<<10011K(01011M)11011L=00111R-10111Q/01111N%11111P+10000A111110D0|

# Phase 1
:
  # Using "@" as a "cursor", substitute for each run of 5 binary digits the
  # two corresponding characters from the lookup table.
  s/@([01]{5})(.*;.*\1)(..)/\3@\2\3/
  t   # Loop (branch to `:`) as long as substitutions are made.

s/@;.*//       # Delete the "@" and lookup table

# Phase 2
s/#f /@/       # FS (f ) in letter mode (#); delete and switch to figure mode (@ cursor).
s/@ l/#/       # LS ( l) in figure mode (@); delete and switch to letter mode (# cursor).
s/#(.)./\1#/   # Letter mode; replace pair with first of pair; advance cursor.
s/@.(.)/\1@/   # Figure mode; replace pair with second of pair; advance cursor.
t              # If any substitutions were made, branch (loop) to `:`.

# Teardown
s/.<|[#@]//g   # Delete characters followed by < (ER) and cursor.

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