Mutually fill in the blanks
Retina, 102 100 93 88 bytes
Byte count assumes ISO 8859-1 encoding.
$
!¶$`
m`(?<=^(\w+ )*)(?=_.*¶(?<-1>\w+ )*(\w+))
$2
(([a-z])+)(?<-2>_)*(_*)\3|!\D+
$3$1$3
The strings will are separated by a linefeed. If there is an odd number of underscores left, the extraneous one will be after the word.
Try it online!
Explanation
I guess this is the "duplicate-append-lookback-match-add-centre approach", or something close...
$
!¶$`
We start by duplicating the input (separated with a !
and a linefeed). The purpose of this is that we can then process both lines by fetching words from the next line (instead of having to treat the second line separately).
m`(?<=^(\w+ )*)(?=_.*¶(?<-1>\w+ )*(\w+))
$2
This prepends the correct word to each gap. We start by counting the current word position with the lookbehind (?<=^(\w+ )*)
(the position is stored as the depth of group 1
). Then the lookahead a) ensures that we're at the beginning of a gap by matching _
, then skips to the next line with .*¶
, matches the correct number of words with (?<-1>\w+ )*
to get to the right position, and then matches the word found there with (\w+)
into group 2
.
(([a-z])+)(?<-2>_)*(_*)\3|!\D+
$3$1$3
This stage does three things:
- It removes the underscores corresponding to each word length. This is done by counting the word length into group
2
with([a-z])+
and then matching that many underscores (which are never written back). - It shifts the word to the centre of the gap by capturing half of the remaining underscores with
(_*)\3
and writing$3$1$3
back. - It removes the duplicated input by matching
!\D+
and replacing it with nothing.
Pyth, 30
jL;Cmm|*}J\_k.[lkhx#JdJkdCcR;Q
Takes input and outputs as a list of two strings. Uses a pretty basic split–zip–double map–centre–zip–join approach.
Try it here
Expanded:
jL;Cmm|*}J\_k.[lkhx#JdJkdCcR;Q ##
cR;Q ## split
C ## zip
mm ## double map
|*}J\_k.[lkhx#JdJkd ## centre
C ## zip
jL; ## join
I'll explain more once I'm really satisfied that I can't golf this any more, although it should be pretty clear, given the ubiquity of the split–zip–double map–centre–zip–join approach and all.
Python 2, 109
def f(a,b):exec"print' '.join([x,y][x<'`'].center(len(x),'_')for x,y in zip(a.split(),b.split()));a,b=b,a;"*2
The function takes two strings as arguments and prints the output as in the examples. It uses a boring approach, with str.center(width, fillchar)
doing most of the work.
Try it online.