Connect the Dots
Ruby, 137 133 bytes
->s{eval"s.split($/).map(&:chars)#{".map{|x|x.join.gsub(/o +(?=o)/){|x|x.tr' ',?|}.chars}.transpose"*2}.map(&:join)*$/".sub'?|','?-'}
This is absolutely horrible. Still trying to golf.
Input as a padded rectangle, please.
Newline for "readability":
eval"s.split($/).map(&:chars)#{".map{|x|x.join.gsub(/o +(?=o)/){|x|x.tr' ',?|}
.chars}.transpose"*2}.map(&:join)*$/".sub'?|','?-'
Japt, 33 29 bytes
Uy eV="o +o"_rS'|} y eV,_rS'-
Test it online!
How it works
Uy // Transpose rows with columns in the input.
eV="o +o" // Set V to the regex-string "o +o", and recursively replace each match Z with:
_rS'|} // Z with spaces replaced with "|"s.
y // Transpose again.
eV, // Recursively replace matches Z of V with:
_rS'- // Z with spaces replaced with "-"s.
Retina, 80 bytes
T` `-`o.+o
Tm` `|`(?<=(?(1)!)^(?<-1>.)*o\D*¶(.)*) (?=(.)*¶\D*o(?<-2>.)*$(?(2)!))
Input needs to be padded.
Try it online!
Explanation
The first stage is pretty simple, it just turns all spaces into hyphens which are found between two o
s in the same line.
The second stage covers the |
s. This is a bit trickier and requires balancing groups. The lookbehind
(?<=(?(1)!)^(?<-1>.)*o\D*¶(.)*)
checks that there's an o
earlier in the same column. Remember that lookbehinds should be read from right to left. (.)*
stores the horizontal position of match, \D*¶
checks skips to any character in the preceding lines, o
matches literally. Then (?(1)!)^(?<-1>.)*
ensures that the horizontal position of that o
is the same.
The lookahead
(?=(.)*¶\D*o(?<-2>.)*$(?(2)!))
Does exactly the same thing in the opposite direction.