GNU sed, 178 + 1 = 179 bytes
+1 byte for -r
flag. Takes input on STDIN.
h
s/./;/g
s/^(;+)..\1$/ \1/
:
s/( *)(;+);;/\1 \2\n\1;;/
t
s/;;/; ;/
:A
s/(( +);\n +);;/\1;\2 ;/
tA
G
s/;(.*\<)(.)/\2\1/
:B
s/;( +);(.*)(\<.)(.*)(.)/\3\1\5\2\4/
tB
s/;\n(.)/\1\n/
Try it online!
Explanation
The program works in two phases. In the phase 1, it creates the top of the triangle. Suppose the input is abcdefghijklmnop
. First, it's copied the hold space. Then each character is replaced with ;
, the second half-plus-one is deleted, and a space is prepended, leaving _;;;;;;;
where _
is a space.
Now, working from the end, the string is split into pairs, with an increasing number of spaces prepended:
┆ ;;;;;;;
┆
┆ ;;;;;
┆ ;;
┆ ;;;
┆ ;;
┆ ;;
┆ ;
┆ ;;
┆ ;;
┆ ;;
Then an increasing number of spaces is inserted between each pair:
┆ ;
┆ ; ;
┆ ;;
┆ ;;
┆ ;
┆ ; ;
┆ ; ;
┆ ;;
┆ ;
┆ ; ;
┆ ; ;
┆ ; ;
In phase 2, the ;
s are replaced with the letters of the string. First the letters are appended from the hold space, and the first ;
is replaced with the first letter, which is deleted:
┆ ;
┆ ; ;
┆ ; ;
┆ ; ;
┆abcdefghijklmnop
┆ a
┆ ; ;
┆ ; ;
┆ ; ;
┆bcdefghijklmnop
Finally each pair of ;
s is replaced with the first and last of the remaining letters, which are deleted:
┆ a
┆ b p
┆ ; ;
┆ ; ;
┆cdefghijklmno
┆ a
┆ b p
┆ c o
┆ ; ;
┆defghijklmn
┆ a
┆ b p
┆ c o
┆ d n
┆efghijklm
There's one special case, which is four-character input. In that case, the result is:
┆ ;
┆abcd
...and a simple substitution fixes it:
┆ a
┆bcd
Here's the annotated code:
# Copy pattern space to hold space
h
# Replace every character with `;`
s/./;/g
# Delete the second half+1 characters, prepend a space
s/^(;+)..\1$/ \1/
# Split the string into pairs, each time prepending one more space than the previous pair
:
s/( *)(;+);;/\1 \2\n\1;;/
t
s/;;/; ;/ # Put a space between the first pair
# Put increasing spaces between subsequent pairs
:A
s/(( +);\n +);;/\1;\2 ;/
tA
# Append hold space to pattern space
G
# Replace the first `;` with the first letter and remove the letter
s/;(.*\<)(.)/\2\1/
# Replace subsequent pairs of `;` with the first and last remaining letters, respectively
:B
s/;( +);(.*)(\<.)(.*)(.)/\3\1\5\2\4/
tB
# Special case: Four characters, ;\nabcd -> a\nbcd
s/;\n(.)/\1\n/