Make the Stretchy Snakes Kiss
Retina, 209 107 99 97 92 bytes

.(?=(.+)(?&lt;=(?=&lt;((\|+|(?&lt;-5&gt;\|(?=\1())?)+)[^|]+)+$(?(5)!)).+( )+\S+))\4
/ \
+` (.*~|~.*) 
$1


For counting purposes, each line goes in a separate file, but you can run the code from a single file with the -s flag.

Bringing the best features of .NET regex and Retina together: balancing groups, arbitrary length lookbehinds and repeated regex substitution.

Essentially, the long regex encodes a valid solution and the regex engine's backtracker finds one of the optimal ones for me.

Explanation

First, let's consider how we can find a valid solution (not necessarily producing the correct output) with a regex. We can use .NET's balancing groups to help us count the stretchy parts. Consider the following simpler regex:

\S+( )+.+(?&lt;=(?(1)!)^([^|]+(\|+|(?&lt;-1&gt;\|)*))+&gt;)


We can disect that.

\S+( )+.+


This matches the entire string, pushing one capture onto the group 1 stack for each space in the input. We will use that stack to ensure that the stretchy parts exactly fill the space captured into those groups.

Next is a lookbehind. The catch is that lookbehinds are matched from right to left in .NET (so that's how you should read them). This gives us the opportunity to traverse the string a second time, figuring out whether there's a subset of stretchy part that sums to the number of matched spaces. Going through the lookbehind from right-to-left:

&gt;


This is just ensure that we're actually starting from the end of the string (the snake's tail).

(
  [^|]+
  (
    \|+
  |
    (?&lt;-1&gt;\|)+
  )
)+


For each stretchy part, this either just matches the entire part without doing anything (\|+), or it matches the entire part while popping captures off stack 1 ((?&lt;-1&gt;\|)*). Having this alternation ensures that we can only fully extend a stretchy part or leave it unchanged, and not get stuff like |/\|. Then we move on to the next stretchy part with [^|]+.

(?(1)!)^


Finally, we ensure that we've traverse the entire string (both snakes), and that stack 1 is completely empty. I.e. that we've found a subset of stretchy part that exactly sums to the number of spaces we've captured earlier.

The backtracker will go back and forth through the string trying all combinations of unchanged and extended parts until the subset sum problem is solved. If such a subset doesn't exist, the lookbehind will fail. This will cause the backtracker to go back to the \S+( )+.+ part and try capturing one space less with ( )+ (which will just be cover by .+ instead). Due to the greediness of + we therefore try filling as many spaces as possible.

You can check the validity of this approach with this slightly modified substitution:

\S+(( )+).+(?&lt;=(?(2)!)^([^|]+(\|+|(?&lt;-2&gt;\|)*))+&gt;)
=$1=


Which will give you a string =spaces= with exactly the number of spaces that can be filled with the given snakes.

I've had to add some more trickery to actually expand the correct |s. Basically, I want to replace all |s which were matched using the (?&lt;-1&gt;\|)+ branch. The idea is to match an individual character, put the solver in a lookaround and set a flag if the match happens to be inside that branch. If that flag wasn't set we invalidate the match at the end to avoid replacement of other characters.

To do this, we use a bunch of nested lookarounds. Again, .NET's variable-length lookbehinds are matched from right to left, so if we nest lookaheads and lookbehinds, we can let the regex engine traverse the string several times. For golfing reasons, the solver is reversed in my actual solution (starting at the end, picking up the spaces from right to left, and then solving the subset sum from left to right), but otherwise the structure of the solver is exactly the same. Let's dissect the full regex:

.(?=(.+)...)


We match a single character, then capture the remainder of the string and move the cursor to the end of the string. We will use this group 1 later to check in the solver whether we're at the position of the match.

(?&lt;=....+( )+\S+)


This is like the first part of the simple solver above, except that we pick up the spaces from right to left. The backtracking of the number of spaces works exactly the same as before, except that we're using group 5 now.

(?=&lt;((\|+|(?&lt;-5&gt;\|(?=\1())?)+)[^|]+)+$(?(5)!))


This is the same as before, except we're going from left to right, and whenever we match a | in the expanding branch, we check if it's the one being matched right with

(?=\1())?


This is an optional lookahead. It tries to match group 1 again (which, here, is only possible if we're right after the character being matched), and if we do, we capture an empty string into group 4, which indicates that we did find the current character in one of the expanded bits. If \1 doesn't match, 4 won't capture anything, and the ? ensures that the failing lookahead won't affect the solver at all.

Finally, after all the solving is done, we just check with \4 whether this lookahead was used. If so, we want to replace the current character with /\.

One difficulty remains: removing the right amount of spaces. The shortest way to do this I've found so far is to insert a space along with the /\ and then get rid of one space between the tongues for each of those marker spaces in a separate step:

+` (.*~|~.*) 
$1