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\$
  • 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 Jul 25 '17 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\$ – Erik the Outgolfer Jul 25 '17 at 13:26
  • \$\begingroup\$ Is this a box or not? \$\endgroup\$ – Cows quack Jul 25 '17 at 14:08
  • \$\begingroup\$ @Cowsquack From the spec it seems it isn't. \$\endgroup\$ – Erik the Outgolfer Jul 25 '17 at 14:12
  • \$\begingroup\$ @Neil Sorry, I mean that any spaces at the beginning would render it as not a box. \$\endgroup\$ – HyperNeutrino Jul 25 '17 at 16:27
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\$
  • \$\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\$ – Erik the Outgolfer Jul 25 '17 at 14:17
  • \$\begingroup\$ Haha, sounds like a commercial for something "now under 2 dollars!" when it costs 1.99 :P \$\endgroup\$ – ETHproductions Jul 25 '17 at 14:22
  • \$\begingroup\$ That's called industrial robbery lol. \$\endgroup\$ – Erik the Outgolfer Jul 25 '17 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\$ – Rick Hitchcock Jul 26 '17 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\$
  • \$\begingroup\$ ⁰I{_=}¹χ is +8 bytes not +7. \$\endgroup\$ – Erik the Outgolfer Jul 25 '17 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 Jul 25 '17 at 14:21
2
\$\begingroup\$

Jelly, 46 bytes

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

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Um this transposes (zips) the input when making it rectangular \$\endgroup\$ – HyperNeutrino Sep 11 '17 at 14:49
  • \$\begingroup\$ @HyperNeutrino I don't remember it doing that when I answered... \$\endgroup\$ – Erik the Outgolfer Sep 11 '17 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, privacy policy and cookie policy

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