Concatenate Strings with Context

Haskell, 184 182 201 199 155

s&t|(a,'|':b)<-f t,(x,'|':y)<-f$r s,x#b,a#y=r(y!r a)++b!r x|0<1=""
r=reverse
a!b=a++drop(length a-1)b
(#)a=and.zipWith(==)(r a).filter h
f=span h
h=(/='|')

example run:

"|a|"&"|b|" -- returns "|ab|"
"|a|x"&"|b|" -- returns ""

if there isn't a match an empty string will be returned. otherwise the result would be returned.

partial explanation:

# is a function which gets two strings, and returns whether or not they match.

! gets two strings and returns the first one concatenated with extra character from the second (if there are any).

the main function & uses span (/='|') to split the inputs into two parts, a|b|c to a, b|c, checks if the contexts match, and then uses ! twice to assemble the output.

Edit: mage-late regolfing seems to be pretty effective.


Python (242 bytes)

import itertools as i
s='|'
j=''.join
r=reversed
m=lambda a,b:j(j(*set(p+q))for p,q in i.izip_longest(a,b,fillvalue=''))
def c(A,B):
 u,v,w,x,y,z=(A+s+B).split(s)
 try:return j(r(m(r(u+v),r(x))))[:-len(v)]+s+v+y+s+m(w,y+z)[len(y):]
 except:0

Explanation

The lambda function m returns the longer of two strings as long as they share a common prefix. It does this by concatenating the empty string '' in place of any missing values, then turning the result (which may take the forms aa, ab, a, or b in cases of match/mismatch/unequal lengths) into a set of unique characters at each position. join expects a single argument, so unpacking a set with more than one element will cause it to raise a TypeError.

The main function then

  • uses m to combine the left context and data part the first word with the left context of the second (from right to left over reversed strings)
  • concatenates data parts,
  • and again uses m to combine the right context of the first word with the data part and right context of the second

The two original words' data parts are trimmed from the right and left sides of the new contexts.

Since we know that misalignments cause m to raise a TypeError, in these cases we catch the exception and implicitly return None.

Testing

TESTCASES = [
    ('aa|bcc|dee', 'cc|de|eee', 'aa|bccde|eee'),
    ('a|bb|cd', 'aabb|cd|', 'aa|bbcd|'),
    ('a|b|cccd', 'aab|cc|c', 'aa|bcc|cd'),
    ('a|b|c', 'b||cd', 'a|b|cd'),
    ('aa|bb|cc', 'c|c|c', None),
    ('aaa|b|c', 'abb|cd|d', None),
    ('|bb|cd', 'abb|c|ed', None),
    ('a|b|c', 'a||cd', None),
]

for A, B, R in TESTCASES:
    print '{:<10} {:<9} -> {}'.format(A, B, c(A, B))

Output

aa|bcc|dee cc|de|eee -> aa|bccde|eee
a|bb|cd    aabb|cd|  -> aa|bbcd|  
a|b|cccd   aab|cc|c  -> aa|bcc|cd 
a|b|c      b||cd     -> a|b|cd    
aa|bb|cc   c|c|c     -> None      
aaa|b|c    abb|cd|d  -> None      
|bb|cd     abb|c|ed  -> None      
a|b|c      a||cd     -> None