9
\$\begingroup\$

Given a string that is potentially boxed in, toggle the box. This becomes clearer in the test cases and explanation.

Input / Output

Input Format

The input will be either a single string separated by CR, LF, or CRLF, or a list of strings. The input format is up to you to decide.

Output Format

The output format must be in the same format as the input.

Explanation + Example

Let's take a boxed string as an example:

+-------------+
|Hello, World!|
+-------------+

To toggle the box, we remove the first and last row and the first and last column. You may assume that there will be no trailing whitespace after the last line (with an optional trailing newline at the end of the last line), and no trailing whitespace on any line, not counting the newline of course.

This would become:

Hello, World!

The Other Way

If the string is not in a box, add a box to it. This is fairly simple; prepend +---...---+ on its own line with k dashes where k is the length of the longest line, and then for each line, pad it with trailing whitespace to match the length of the longest line and then prepend and append a pipe character ("|"). Finally, append a line containing the same +---...---+ setup as the first line.

For example:

Hello, World!

becomes:

+-------------+
|Hello, World!|
+-------------+

You may assume that none of the lines in the input will have trailing whitespace.

Another example of a string that should have a box put around it:

Hello,
    World!

becomes

+----------+
|Hello,    |
|    World!|
+----------+

An example of something that should still be boxed:

+--------+
|        |
 --------+

becomes:

+----------+
|+--------+|
||        ||
| --------+|
+----------+

Rules + Specifications

  • Standard Loopholes Apply
  • No line of input will have any leading or trailing whitespace both overall and in each line, regardless of whether or not it has been boxed in
  • Boxes will only have + as their corners and | for the vertical edges and - for the horizontal sides.
  • A box must have its pluses in place to be considered a box; if it has height or width 2 (that is, no content), it should still be unboxed, which would result in a bunch of newlines, depending on the height of the box.
  • If the input has a box but text outside of the box, the whole thing should be boxed.
  • Your program must check the entire perimeter of the string. If a single character along the outside is not correct (either missing or a different character than what it should be), then it should be boxed, not unboxed.
  • The unboxed string itself may contain + | -. If the unboxed string itself has a box around it, return the string with the box; it should only be unboxed once.

Edge Cases

1: Small boxes

Input:

++
++

Output is a empty or a newline

Input:

+----+
+----+

Output is empty or a newline

Input:

++
||
||
++

Output is 2 newlines or 3 newlines

2: Partial Box

Input:

+-------+
| Hello |
+ ------+

Output:

+---------+
|+-------+|
|| Hello ||
|+ ------+|
+---------+

3: Text outside of box

Input:

 +-------+
a| Hello |
 +-------+

Output:

+----------+
| +-------+|
|a| Hello ||
| +-------+|
+----------+
\$\endgroup\$
7
  • 1
    \$\begingroup\$ "No line of input will have any leading or trailing whitespace both overall and in each line, regardless of whether or not it has been boxed in." Several of your test cases have leading whitespace. Would rectangular input be too much to ask? \$\endgroup\$
    – Neil
    Commented Jul 25, 2017 at 7:53
  • \$\begingroup\$ @Neil He probably meant no consistent leading whitespace, i.e. each line starting with 3 spaces wouldn't be a case but lines starting with 1, 2, 0, 3 spaces would since those aren't consistent. \$\endgroup\$ Commented Jul 25, 2017 at 13:26
  • \$\begingroup\$ Is this a box or not? \$\endgroup\$
    – user41805
    Commented Jul 25, 2017 at 14:08
  • \$\begingroup\$ @Cowsquack From the spec it seems it isn't. \$\endgroup\$ Commented Jul 25, 2017 at 14:12
  • \$\begingroup\$ @Neil Sorry, I mean that any spaces at the beginning would render it as not a box. \$\endgroup\$
    – hyperneutrino
    Commented Jul 25, 2017 at 16:27

4 Answers 4

6
\$\begingroup\$

JavaScript (ES2017), 199 bytes

s=>/^\+-*\+\n(\|.*\|\n)*\+-*\+$/.test(s,s=s.split`
`,s.map(z=>z[y]?y=z.length:0,y=0))?s.slice(1,-1).join`
`.replace(/.(.*)./g,"$1"):(x=`+${'-'.repeat(y)}+`)+`
|${s.map(z=>z.padEnd(y)).join`|
|`}|
`+x

The naive solution. May or not be the best, we'll see...

\$\endgroup\$
4
  • \$\begingroup\$ "May or not be the best, we'll see..." still it's cool to see a non-golfing language such as JS to solve this in <200 bytes...see what I did there? ;) \$\endgroup\$ Commented Jul 25, 2017 at 14:17
  • \$\begingroup\$ Haha, sounds like a commercial for something "now under 2 dollars!" when it costs 1.99 :P \$\endgroup\$ Commented Jul 25, 2017 at 14:22
  • \$\begingroup\$ That's called industrial robbery lol. \$\endgroup\$ Commented Jul 25, 2017 at 14:29
  • \$\begingroup\$ This works for the test cases, but I don't think it works for something like this: '+--+\n|hi|\n|world|\n+----------+'. It removes the lines, even though it's not rectangular. \$\endgroup\$ Commented Jul 26, 2017 at 22:17
3
\$\begingroup\$

SOGL V0.12, 72 bytes

2-┌* +1Ο;2-⁴┌@ŗΖ+|ŗ∙⁴++B
▓Aa1w⁄;lGB╬8a⁰I{_=}¹χ?ajk{jk}⁰←a1w⁄;l2+G2+B00╬5

Try it Here!

+7 bytes (⁰I{_=}¹χ) because elementwise equals isn't implemented
+1 byte ()because input isn't guaranteed to be square
+1 byte (A) for me being lazy and not implementing typed inputs (so this expects input on the stack. For ease-of-use, the online link includes → so the input box can be used)

\$\endgroup\$
2
  • \$\begingroup\$ ⁰I{_=}¹χ is +8 bytes not +7. \$\endgroup\$ Commented Jul 25, 2017 at 14:20
  • \$\begingroup\$ @EriktheOutgolfer well the replacement should be =, but as that doesn't work, it changes length by -1+8 = +7 \$\endgroup\$
    – dzaima
    Commented Jul 25, 2017 at 14:21
2
\$\begingroup\$

Jelly, 46 bytes

ẋ2jЀ
z©⁶”|çZṖ”-çµḢ⁾-+yWWçWẎZ
ḊṖZḊṖÇ
Ỵ®2ĿÇ⁼$?Y

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Um this transposes (zips) the input when making it rectangular \$\endgroup\$
    – hyperneutrino
    Commented Sep 11, 2017 at 14:49
  • \$\begingroup\$ @HyperNeutrino I don't remember it doing that when I answered... \$\endgroup\$ Commented Sep 11, 2017 at 14:51
2
\$\begingroup\$

Retina, 197 195 bytes

+m`^((.)*)(¶(?<-2>.)*(?(2)$|(.)))
$1$#4$* $3$#2$* 
%`^|$
|
^.(.*).
+$.1$*-+¶$&
.(.*).$
$&¶+$.1$*-+
^(\+-*\+)¶(\|\+-*\+\|)¶(\|\|.*\|\|¶)*\2¶\1$
¶$&¶
..(.*)..(?=(.|¶)*¶$)
$1
^¶-*¶-*¶|(\G|¶)-*¶-*¶$

Try it online! Explanation:

+m`^((.)*)(¶(?<-2>.)*(?(2)$|(.)))
$1$#4$* $3$#2$* 

This stage is quite complicated in itself, so I'll break it down a bit. + means that the stage repeats until no more replacements can be found. m`^ means that the stage matches at the start of any line. ((.)*) then matches the whole line. Now $1 is simply the matched line, but $2 is a list of matches i.e. characters. then matches the end of the line and therefore the start of the next line. (?<-2>.)* uses a .NET balancing group. The <-2> removes matches from $2 as long as a character can be matched on the second line. At this point, one of three things can happen:

  • There weren't enough characters on the second line. $2 still has some matches left.
  • The two lines were exactly the same length. $2 has no matches left, and we are at the end of the line.
  • The second line is longer, so there is at least one character left over.

(?(2)$|(.))) helps distinguish these using a condition. If $2 still has some matches left, then we need this to be because the second line is too short, so we match the end of the line, but if $2 has no matches left, then we want the second line to be longer, so we match a character (which goes into $4 so that we know that the match happened). Otherwise the two lines are the same length and the match fails at this point (it might match again at a later line of course).

The replacement string is $1$#4$* $3$#2$*. The $#4 evaluates to 1 if we matched an additional character on the second line, 0 if not. This means that $#4$* adds a space to the first line if the second line was longer. Similarly $#2$* adds spaces to the second line if the first line was longer. (In fact, it ends up adding exactly the right number of spaces. If we were only balancing two lines, a + could have been added to the fourth capture group to achieve this directly for the case of the longer second line too.)

The upshot of all this is that this stage pads out the input into a rectangle. We can now draw a box around it.

%`^|$
|

Place |s on each side.

^.(.*).
+$.1$*-+¶$&

Place +-...-+ on the top.

.(.*).$
$&¶+$.1$*-+

And again on the bottom.

^(\+-*\+)¶(\|\+-*\+\|)¶(\|\|.*\|\|¶)*\2¶\1$
¶$&¶

See if we've created a double box. If so, extra blank lines are added at the top and bottom for the remaining stages to match to delete both boxes.

..(.*)..(?=(.|¶)*¶$)
$1

If there's a trailing blank line, remove two characters from the start and end of every line.

^¶-*¶-*¶|(\G|¶)-*¶-*¶$

If there's a leading blank line, delete it and the next two lines (which will be the -s remaining at the top of the box). If there's a trailing blank line, delete it and the previous two lines. The (\G|¶) deals with the case where there's only six lines (and therefore 5 s) because the box had no content.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.