Carve a square from a string

Husk, 13 bytes


Try it online!


►oΛ≈S+TzṀ↑Nḣ¶  Implicit input, say "ab\nc".
            ¶  Split at newlines: ["ab","c"]
           ḣ   Take prefixes: [["ab"],["ab","c"]]
       z  N    Zip with [1,2,3..
        Ṁ↑     by taking that many characters from each row: [["a"],["ab","c"]]
►o             Find rightmost element that satisfies this:
  Λ            all strings in
    S+T        the list concatenated to its transpose
   ≈           have the same length: ["a"]
               Implicitly print separated by newlines.

GNU sed, 106 + 1 94 + 2 = 96 bytes

+2 bytes for -rz flags. Uses unprintable characters NUL and BEL, shown as @ and # here. See below for an xxd dump.

Thanks to @seshoumara for sending me down the path to -z.

s/@(.)/\[email protected]/mg

Try it online!


This works by inserting two cursors into the text—one to step over lines and one to step over columns. The cursors are represented by NUL (0x00) and BEL (0x07), respectively, but in the below examples I'll use @ and #. Suppose we have this input:


The BEL cursor is inserted before the 0th column and the BEL cursor before the 0th line (here I've kept the columns aligned for legibility; but in actuality there is no left padding):


In a loop, the cursors are moved one character to the right and one line down, respectively:

 [email protected]
#[email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]
#[email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]
#[email protected]

After each iteration, it checks two conditions:

  1. On the line with the line cursor, is there a column cursor and can the column cursor move to the right?
  2. On the lines before the line cursor, can every column cursor move to the right?

If either condition is false, the loop ends. The script finishes by deleting everything after @ on each line and everything after # in the pattern space.

xxd dump

00000000: 732f 5e2f 002f 676d 0a73 2f2e 2a2f 0726  s/^/./gm.s/.*/.&
00000010: 5c6e 2f0a 3a42 0a73 2f00 282e 292f 5c31  \n/.:B.s/.(.)/\1
00000020: 002f 6d67 0a73 2f07 282e 2b5c 6e29 2f5c  ./mg.s/.(.+\n)/\
00000030: 3107 2f6d 0a2f 072e 2a00 2e2f 4d21 620a  1./m./..*../M!b.
00000040: 2f00 5c6e 2e2a 072f 2162 420a 3a0a 732f  /.\n.*./!bB.:.s/
00000050: 005b 5e5c 6e5d 2a7c 072e 2a2f 2f67       .[^\n]*|..*//g

Brachylog, 11 bytes


Try it online!


ṇ             Split on linebreaks
 ⊇ᵐ           Take a subset of each line
   ẹ          Split the lines into list of chars
    a₀        Take a prefix of this list of lists of chars
      ṁ       It is a square matrix
       cᵐ     Concatenate the list of chars back into strings
         ~ṇ   Join the strings with linebreaks