Given a table, place in the chairs Challenge

You will be given a table as input, drawn with ASCII | and _. Your task is to set the chairs around it.

Example

Input:

 ____
|    |
|    |
|    |
|    |
|____|


Output:

 _^_^_
&lt;     &gt;
|     |
&lt;     &gt;
|     |
&lt;_ _ _&gt;
  v v


Those chairs are made of &lt;&gt; and v^.

Another example:

The line must have as many chairs as possible in it.

  _____
 |     |_____
 |           |
 |           |
 |           |
 |      _____|
 |_____|


  _^_^_
 &lt;     |_^_^_
 |           &gt;
 &lt;           |
 |           |
 &lt;      _ _ _&gt;
 |_ _ _| v v
   v v


There must be spaces between every chair. And &gt;_^_^_&lt; is invalid, it should be |_^_^_|.

  _____       _____
 |     |_____|     |
 |                 |
 |                 |
 |                 |
 |      ___________|
 |_____|


  _^_^_       _^_^_
 &lt;     |_^_^_|     &gt;
 |                 |
 &lt;                 &gt;
 |                 |
 &lt;      _ _ _ _ _ _&gt;
 |_ _ _| v v v v v
   v v


No chairs may be on the inside of a "donut".

  _________________
 |      _____      |
 |     |     |     |
 |     |     |     |
 |     |_____|     |
 |_________________|


  _^_^_^_^_^_^_^_^_
 &lt;      _____      &gt;
 |     |     |     |
 &lt;     |     |     &gt;
 |     |_____|     |
 &lt;_ _ _ _ _ _ _ _ _&gt;
   v v v v v v v v


^ and v prioritise &lt; and &gt;. No chair on it's own (it has to have at least one | or _ in the row).

  _________________
 |      _____      |
 |     |     |     |
 |     |     |_____|
 |     |_____
 |___________|


  _^_^_^_^_^_^_^_^_
 &lt;      _ _ _      &gt;
 |     | v v |     |
 &lt;     &gt;     &lt;_ _ _&gt;
 |     |_^_^_  v v
 &lt;_ _ _ _ _ _|
   v v v v v


This is code golf, so shortest code wins.
Python 2, 1033 1007 924 879 829 787 713 699 692 691 688 687 672 670 664 659 654 648 643 642 630 625 623 620 570 560 554 545 518 514 513 510 505 492 476 454 451 443 bytes
6 bytes saved thanks to Riley
6 bytes saved thanks to Adnan

Since this question is over a year old and still has no answers I thought I'd give it a try.
n,i,o,u=&quot;\nI _&quot;;R=lambda x:range(1,x-1)
b=open(i).read()
s=b.split(n)
z=max(map(len,s))+3
a=[list(i+x.ljust(z,i))for x in[i]+s+[i]]
for x in R(len(a))*len(b):
 A=a[x];B=a[x+1];C=a[x-1]
 for y in R(z):
    D=A[y-1:y+2];k=B[y];j=A[y+1]
    if(i in[C[y],k]+D+(k==u)*B[y-1:y+2]or&quot;V&quot;==j)&amp;(A[y]==o):A[y]=i
    if&quot;|&quot;==A[y]==C[y]:A[y]={i:&quot;|&quot;,j:&quot;&gt;&quot;,A[y-1]:&quot;&lt;&quot;}[i]
    if[u]*3==D:A[y],B[y]={i:u+k,C[y]:&quot;^&quot;+k,k:&quot; V&quot;}[i]
print n.join(`y`[2::5]for y in a).replace(i,o)

Try it online!
The program reads the table a file named I and prints the table with its chairs to std::out.  I was not sure about a bunch of the edge cases so I took my best judgement (whatever took the least effort) but it seems to pass all the test cases.  Some of the outputs don't match exactly but they all have the same number of chairs.
Explanation
The first line pretty simply sets up some definitions that will save us bytes in the future:
(I will unpack these macros for readability in future lines)
n,i,o=&quot;\nI &quot;;R=lambda x:range(1,x-1)

Then we will open a file named I because we already have a variable that is short for that so it saves a few bytes.
b=open(&quot;I&quot;).read().split(&quot;\n&quot;)

We split along newlines to create a list of strings (The rows of the image)
s=b.split(n)

I then find the length of the longest line so that I can pad all lines to that length.  (I also add 3 because we need a bit of additional padding)
 z=max(map(len,s))+3

Then we perform the actual padding and create a border of I characters around the edge.  This is because we will need to tell the difference between the inside and the outside of the shape later on.  We will also change the data type from a list of strings to a list of list of characters (length 1 strings).
a=[list(&quot;I&quot;+x.ljust(z,&quot;I&quot;))for x in[&quot;I&quot;]+s+[&quot;I&quot;]]

The next line is just another byte saving definition.
(I will also unpack this one)
B=R(len(a))

Now we want to spread I characters to everywhere outside of the shape.  We can do this with a pseudo-cellular automaton.  Each I will spread to any adjacent   characters.  We could loop until the automaton stabilizes however this cannot take more iterations than there are characters so we just loop through every character in b (the original input)
for _ in b:

For each iteration we want to pass over every character in the 2D list (excluding the outermost padding)
 for x in range(1,len(a)-1):
    A=a[x]  #&lt;--Another definition I will fill in for clarity
    for y in range(1,z-1):

For each position we run the following code:
if(&quot;I&quot; in[a[x+1][y],a[x-1][y]]+a[x][y-1:y+2])&amp;(a[x][y]==&quot; &quot;):a[x][y]=&quot; &quot;

Lets break this down.
We have an if with two conditions separated by a &amp; (bitwise and)
The first one simply checks if there is an I in any of the adjacent cells and the second one just checks if the current cell is a &quot; &quot;.  If we pass those conditions we set the current cell to be an I.

Now that we have determined the outside and inside of the shape we can start to place the chairs around the table.
Once again we loop through all of the cells (and set some more shorthands)
for x in range(1,len(a)-1):
 A=a[x]
 for y in range(1,z-1):
        k=a[x+1][y]
 

Now here's my favorite part.  If you have trudged through my boring, mostly definition based, golfing so far I am going to reward you with a nice tidbit of clever golfing (if I do say so myself).
A little background in python:
In Python if you attempt to assign an dictionary key twice it asigns the latter one.  For example
&gt;&gt;&gt; {1:&quot;a&quot;,1:&quot;b&quot;}[1]
'b'

We will abuse this property to assign the current cell to a particular character.
The first condition is
if[&quot;_&quot;]*3==a[x][y-1:y+2]:a[x][y],a[x+1][y]={&quot;I&quot;:&quot;_&quot;+a[x+1][y],a[x-1][y]:&quot;^ &quot;,a[x+1][y]:&quot; V&quot;}[&quot;I&quot;]

If the cell is in the middle of an edge of 3 _ characters we will reassign the current cell and the cell below it.  We will assign it to the result of indexing an overloaded dictionary by I.  We first set our default with the pair &quot;I&quot;:&quot;_&quot;+a[x+1][y] this means if there is no change we will assign the two cells back to their original values.  Next we add the pair a[x-1][y]:&quot;^ &quot;.  This wont do anything (important) unless the cell above the current one (a[x-1][y]) is filled with an I.  If it has an I in it it will override the default telling us to place a chair at the current cell.  Next we move on to the cell below the current cell if that cell is I we again override to place an upwards facing chair below the current spot.
The next condition is a tad simpler
if&quot;|&quot;==a[x][y]==a[x-1][y]:a[x][y]={&quot;I&quot;:&quot;|&quot;,A[y+1]:&quot;&gt;&quot;,A[y-1]:&quot;&lt;&quot;}[&quot;I&quot;]   

We check if the current cell and the cell above it are both |.  If so we set up a dictionary.
The first pair in the dictionary &quot;I&quot;:&quot;|&quot; sets the default.  Since we are going to access the key I if I does not get reassigned it will default back to | (the character it already is) and do nothing.
We the add the two keys A[y+1]:&quot;&gt;&quot;,A[y-1]:&quot;&lt;&quot; If either of the two cells to the left and right are I then it will reassign the current cell to a chair pointing in the direction of the outside.

Now we just have to output.  However we can't just print,  there are a couple of housekeeping things we have to do first.  We have to convert back to a string and remove all of the Is we created.  This is done in one line.
print &quot;\n&quot;.join(`y`[2::5]for y in a).replace(&quot;I&quot;,&quot; &quot;)