Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Introduction

I think everyone agrees that nice pictures have to have a nice frame. But most challenges on this site about ASCII-Art just want the raw picture and don't care about it's preservation.
Wouldn't it be nice if we had a program that takes some ASCII-Art and surrounds it with a nice frame?

The Challenge

Write a program that takes some ASCII-Art as input and outputs it surrounded by a nice frame.

Example:

*****
 ***
  *
 ***
*****

becomes

╔═══════╗
║ ***** ║
║  ***  ║
║   *   ║
║  ***  ║
║ ***** ║
╚═══════╝
  • You have to use the exact same characters for the frame as in the example: ═ ║ ╔ ╗ ╚ ╝
  • The top and the bottom of the frame get inserted before the first and after the last line of the input.
  • The left and rights parts of the frame have to have exact one space padding to the widest line of the input.
  • There may be no leading or trailing whitespaces in the output. Only a trailing newline is allowed.
  • You may assume that the input has no unnecessary leading whitespaces.
  • You may assume that the input has no trailing whitespaces on any line.
  • You don't have to handle empty input.
  • The input will only contain printable ASCII-characters and newlines.

Rules

Happy Coding!

Using some great ASCII-Art, that was produced in any challenge on this site, as input to your program and showing it with a nice frame is highly encouraged!

share|improve this question
24  
A non-ASCII frame for ASCII art? Heresy! – Dennis Feb 16 at 18:27
5  
Very closely related. Same challenge, but only using a single (ASCII) character for the frame. – Martin Büttner Feb 16 at 18:31
12  
(I should clarify I don't think it's a dupe. Having to use 6 different characters makes this a lot trickier. The other challenge can be solved by rotating the grid and appending # four times. Adapting such an approach here will be tricky at best, and not viable at worst.) – Martin Büttner Feb 16 at 18:38
6  
@IsmaelMiguel I have won the previous contest and don't see how I could adapt my old answer at all. – Martin Büttner Feb 17 at 6:31
2  
I suspect that DenkerAffe is assuming CP437 or something where the frame chars are also one byte. – Joshua Feb 17 at 18:48

11 Answers 11

up vote 5 down vote accepted

CJam, 45 chars / 52 bytes

qN/_z,)[_)'═*N]2*C,3%'╔f+.\4/@@f{Se]'║S@2$N}*

Trying to avoid those expensive 3-byte chars was... interesting.

Try it online

Explanation

qN/                   Split input by newline
_z,                   Zip and get length L, i.e. length of longest line
)                     Increment -> L+1
[_)'═*N]              Make two-element array of "═"*(L+2) and newline
2*                    Double the array, giving ["═"*(L+2) "\n" "═"*(L+2) "\n"]

C,                    range(12), i.e. [0 1 2 ... 11]
3%                    Every third element, i.e. [0 3 6 9]
'╔f+                  Add "╔" to each, giving "╔╗╚╝"
.\                    Vectorised swap with the previous array, giving
                      ["╔" "═"*(L+2) "╗" "\n" "╚" "═"*(L+2) "╝" "\n"]
4/                    Split into chunks of length 4

@@                    Move split input and L+1 to top
f{...}                Map with L+1 as extra parameter...
  Se]                   Pad line to length L+1, with spaces
  '║S                   Put "║" and space before it
  2$N                   Put "║" and newline after it

*                     Join, putting the formatted lines between the top and bottom rows
share|improve this answer

Haskell, 139 bytes

q=length
g x|l<-lines x,m<-maximum$q<$>l,s<-[-1..m]>>"═"='╔':s++"╗\n"++(l>>= \z->"║ "++z++([q z..m]>>" ")++"║\n")++'╚':s++"╝"

As an example I'm framing snowman "12333321".

*Main> putStrLn $ g " _===_\n (O.O)\n/(] [)\\\n ( : )"
╔═════════╗
║  _===_  ║
║  (O.O)  ║
║ /(] [)\ ║
║  ( : )  ║
╚═════════╝

How it works:

bind
  l: input split into lines
  m: maximum line length
  s: m+2 times ═

build top line
prepend left frame to each line, pad with spaces, append right frame
build bottom line.
share|improve this answer
6  
+1 for cute snowman – iismathwizard Feb 17 at 20:38

JavaScript (ES6), 138 bytes

This is 138 bytes in the IBM866 encoding, which at time of writing is still supported in Firefox, but 152 in UTF-8.

s=>`╔${t='═'.repeat(w=2+Math.max(...(a=s.split`
`).map(s=>s.length)))}╗
${a.map(s=>('║ '+s+' '.repeat(w)).slice(0,w+1)).join`║
`}║
╚${t}╝`
share|improve this answer
1  
Can you actually encode Javascript using CP437 and still run it? If not, then this isn't actually 138 bytes. – Mama Fun Roll Feb 17 at 4:28
    
@ӍѲꝆΛҐӍΛПҒЦꝆ Although I couldn't find anything supporting CP437, Firefox currently supports IBM866 which also has these box drawing characters, so I've updated my answer. – Neil Feb 17 at 9:01
    
Okay, cool. Have an upvote! – Mama Fun Roll Feb 17 at 14:20

Bash, 173 171 150 148 147 bytes, 157 136 134 133 characters

q(){((n=${#2}>n?${#2}:n));};mapfile -tc1 -C q v;for((p=++n+1;p;--p));do z+=═;done;echo ╔$z╗;printf "║ %-${n}s║\n" "${v[@]}";echo ╚$z╝

Multiline:

q() {
    (( n = ${#2} > n ? ${#2} : n))
}
mapfile -tc1 -C q v

for((p=++n+1;p;--p))
do 
    z+=═
done

echo ╔$z╗
printf "║ %-${n}s║\n" "${v[@]}"
echo ╚$z╝

Example execution:

bash -c 'q(){((n=${#2}>n?${#2}:n));};mapfile -tc1 -C q v;for((p=++n+1;p;--p));do z+=═;done;echo ╔$z╗;printf "║ %-${n}s║\n" "${v[@]}";echo ╚$z╝'< bear.txt

Sample run from script:

$ cat bear2.txt 
     (()__(()
     /       \
    ( /    \  \
     \ o o    /
     (_()_)__/ \
    / _,==.____ \
   (   |--|      )
   /\_.|__|'-.__/\_
  / (        /     \
  \  \      (      /
   )  '._____)    /
(((____.--(((____/mrf
$ ./frame< bear2.txt 
╔═══════════════════════╗
║      (()__(()         ║
║      /       \        ║
║     ( /    \  \       ║
║      \ o o    /       ║
║      (_()_)__/ \      ║
║     / _,==.____ \     ║
║    (   |--|      )    ║
║    /\_.|__|'-.__/\_   ║
║   / (        /     \  ║
║   \  \      (      /  ║
║    )  '._____)    /   ║
║ (((____.--(((____/mrf ║
╚═══════════════════════╝
share|improve this answer
1  
Your example has an emtpy line between the bottom frame and the input which is invalid. The top and bottom frames have to be inserted directly before and after the input (your previous version was fine btw). – DenkerAffe Feb 17 at 8:19
1  
Nice!, But you could save approx 5 char if ...?${#2}+2:n)) instead of +1, drop 2 spaces and printf -v z %${n}s; instead of printf -v z " %*.s" $n. – F. Hauri Feb 17 at 13:59
    
@Sukminder Ok, was already assumnig that, but wanted to make that sure since the input you show does not contain an empty line. I did not demand that you clear the input of leading or traliing empty lines, so you program is perfectly fine. – DenkerAffe Feb 18 at 7:02

AWK, 159 bytes

{a[NR]=$0
x=length($0)
m=m<x?x:m
a[NR,1]=x}
END{for(;i<m+2;i++)t=t"═"
print"╔"t"╗"
for(j=1;j<NR;j++){f="║ %-"m"s ║\n"
printf f,a[j]}print"╚"t"╝"}

Apparently awk can print Unicode if you can figure out how to get it in the code.

share|improve this answer
    
I'm having so many ideas for awesome pipes now ... – Sebb Feb 17 at 23:22
    
@Sebb That does seem like fun. :) – Robert Benson Feb 18 at 13:52

Perl, 111 characters

(score includes +5 for the interpreter flags)

#!/usr/bin/perl -n0 -aF\n
$n=(sort{$b<=>$a}map length,@F)[0];$l="═"x$n;
print"╔═$l═╗\n",(map{sprintf"║ %-${n}s ║\n",$_}@F),"╚═$l═╝";

First, we find the longest line length $n, by numerically sorting the lengths of all lines.

We set $l to be the header/footer bar to be $n repetitions of the horizontal frame character.

Then we print each line formatted to left-align in a field of width $n, sandwiched in between the frame characters.

Result:

╔═══════════╗
║   |\_/|   ║
║  / @ @ \  ║
║ ( > * < ) ║
║  `>>x<<'  ║
║  /  O  \  ║
╚═══════════╝
share|improve this answer

Pyth, 44 chars (58 bytes)

++\╔K*JhheSlR.z\═\╗jbm+\║+.[+;d;J\║.z++\╚K\╝

Explanation

++\╔K*JhheSlR.z\═\╗                          - print out the first line
           lR.z                              -        map(len, all_input())
          S                                  -       sorted(^)
         e                                   -      ^[-1]
       hh                                    -     ^+2
      J                                      -    autoassign J = ^
     *         \═                            -   ^*"═"
    K                                        -  autoassign K = ^
++\╔             \╗                          - imp_print("╔"+^+"╗")

                   jbm+\║+.[+;d;J\║.z        - print out the middle
                   jb                        - "\n".join(V)
                     m             .z        -  [V for d in all_input()]
                      +\║+       \║          -   "║"+V+"║"
                          .[   ;J            -    pad(V, " ", J)
                            +;d              -     " "+d

                                     ++\╚K\╝ - print out the end
                                     ++\╚K\╝ - imp_print("╚"+K+"╝")

Try it here.

share|improve this answer

PHP 5.3, 209 bytes

This only works using the encoding OEM 860. It is an Extended ASCII superset, used in Portuguese DOS versions. Since I'm Portuguese (and I used to love doing these "frames" in Pascal) and this is a standard encoding, I went ahead with this:

<?foreach($W=explode('
',$argv[1])as$v)$M=max($M,strlen($v)+2);printf("É%'Í{$M}s»
º%1\${$M}sº
%2\$s
º%1\${$M}sº
È%1\$'Í{$M}s¼",'',join('
',array_map(function($v)use($M){return str_pad(" $v ",$M);},$W)));

Here's the base64:

PD9mb3JlYWNoKCRXPWV4cGxvZGUoJwonLCRhcmd2WzFdKWFzJHYpJE09bWF4KCRNLHN0cmxlbigkdikrMik7cHJpbnRmKCLilZQlJ+KVkHskTX1z4pWXCuKVkSUxXCR7JE19c+KVkQolMlwkcwrilZElMVwkeyRNfXPilZEK4pWaJTFcJCfilZB7JE19c+KVnSIsJycsam9pbignCicsYXJyYXlfbWFwKGZ1bmN0aW9uKCR2KXVzZSgkTSl7cmV0dXJuIHN0cl9wYWQoIiAkdiAiLCRNKTt9LCRXKSkpOw==

This answer was based on my answer on: http://codegolf.stackexchange.com/a/57883/14732 (the heavy lifting was all made there, just had to twitch a bit).

share|improve this answer
    
Impressive to say the least :) – MonkeyZeus Feb 17 at 21:39
    
The codes is 209 bytes/characters. 22+58+11+5+11+24+66+12=209 The last 12 is newlines and as it is DOS that means CRLF, or two bytes per newline. The charactercountonline site does not count newlines. Each of the non-ASCII glyphs are 1 byte in OEM 860. – Runium Feb 17 at 23:39
    
@Sukminder Don't forget that (at least) Windows converts \n into \r\n, when opening the file in ASCII/text mode. – Ismael Miguel Feb 17 at 23:43

Python 3, 119 Bytes

def f(x): 
 n='\n';s="║ ";e=" ║";h=(x.find(n)+2)*"═";return"╔"+h+"╗"+n+s+x.replace(n,e+n+s)+e+n+"╚"+h+"╝"

126 bytes

import sys
o=["║ %s ║\n"%j[:-1] for j in sys.stdin]
h="═"*(len(o[0])-3)
print("╔"+h+"╗\n"+"".join(o)+"╚"+h+"╝")

Input:

hello
there
  !  

Output:

╔═══════╗
║ hello ║
║ there ║
║   !   ║
╚═══════╝
share|improve this answer
    
Welcome to Progamming Puzzles & Code Golf! Nice first answer! You can always write functions instead of full programs (unless explicitly forbidden in the challenge) which might allow you to save some bytes by taking the input as argument. Also you might want to use Python 2, so you can save 2 bytes by going with print"╔"+h+"╗\n"+"".join(o)+"╚"+h+"╝". – DenkerAffe Feb 19 at 10:49
    
Thanks. I couldn't figure out how to get the high-bytes working in Python2 (probably setting the codec environment variable would work but I'm not sure how that plays into golf byte counts). The function approach eliminates python2/3 differences but adds a byte in my best approach. – SumnerHayes Feb 19 at 18:58
    
Okay, I got it down to 119 characters as a function; takes input as a string. My mini-markdown is obviously not up to snuff; Line 1 is the def, the rest (after the colon) is line 2, with a leading space. def f(x): n='\n';s="║ ";e=" ║";h=(x.find(n)+2)*"═";return"╔"+h+"╗"+n+s+x.replace(n,e+n+s)+e+n+"╚"+h+"╝" – SumnerHayes Feb 19 at 21:45
    
Just update your post with the new version and the new score (struck the old score out with <s>...</s>). Also you can add <!-- language-all: lang-python --> before your code-block to add syntax highlighting to your code. – DenkerAffe Feb 19 at 22:33
    
Thanks! Updated. – SumnerHayes Feb 19 at 23:02

Python 2, 115 Bytes

def f(i):w='═'*(i.find('\n')+2);return'╔%s╗\n║ %s ║\n╚%s╝'%(w,' ║\n║ '.join(i.split('\n')),w)

Looks shorter than 115 here, but working file includes 3-byte UTF-8 BOM mark signature, bumping it up to 115 bytes. If you were to run it in Python 3 you wouldn't need the BOM and it'd get down to 112 bytes.

share|improve this answer
    
Welcome to Programming Puzzles & Code Golf! Unfortunately, your code appears to assume that the input is rectangular, while the question says that no line will have trailing whitespace. – Dennis Feb 23 at 20:33
    
I count 107 bytes. I don't think you need to include the "UTF-8 BOM mark signature". – CalculatorFeline Mar 16 at 15:36
    
@CatsAreFluffy Are you using Python2? In Python3 all strings are unicode, but it's trickier with Python2. – Jenny Miller Mar 18 at 16:51
    
Oops, I counted pipes as 2 bytes, but even after using an actual bytecounter, still only 111 bytes. Tell me where those 5 bytes came from. – CalculatorFeline Mar 18 at 16:57
    
The UTF-8 BOM is 3 bytes (en.wikipedia.org/wiki/Byte_order_mark). My count was one high because my text editor was adding a trailing newline, so my solution is really only 115 bytes. You could leave off the leading BOM bytes and get it down to 112 if you were using Python3 (which counts all strings as unicode). But I don't know how you're seeing only 111 bytes. btw, here's how I added the BOM: sed -i '1s/^\(\xef\xbb\xbf\)\?/\xef\xbb\xbf/' codeGolf.py – Jenny Miller Mar 22 at 19:49

C, 290 bytes

Golfed function B, with dependencies; takes input as null-terminated char*

#define l(s) strlen(s)
p(char*s,int n){while(n--)printf(s);}
B(char*s){char*t=strtok(s,"\n");int x=l(t),z=1;while(t=strtok(0,"\n"))z++,x=l(t)>x?l(t):x;p("╔",1);p("=",x+2);p("╗\n",1);while(z--)printf("║ %s", s),p(" ",x-l(s)),p(" ║\n",1),s+=l(s)+1;p("╚",1);p("=",x+2);p("╝\n",1);}

Somewhat-ungolfed function in full program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1024

// GOLF-BEGIN =>
#define l(s) strlen(s)
// since multibyte chars don't fit in char: use char* instead
void p (char*s,int n){ while(n--)printf(s); } 
void B (char *s){
    char *t = strtok(s,"\n");
    int x=l(t), z=1;
    while(t=strtok(0,"\n"))z++,x=l(t)>x?l(t):x;  
    // x is l(longest line), z is #lines
    p("╔",1);p("=",x+2);p("╗\n",1);
    while(z--)printf("║ %s", s),p(" ",x-l(s)),p(" ║\n",1),s+=l(s)+1;
    p("╚",1);p("=",x+2);p("╝\n",1);       
}
// <= GOLF-END

int main(int argc, char **argv) {
    char buffer[MAX];
    memset(buffer, 0, MAX);
    FILE *f = fopen(argv[1], "rb");
    fread(buffer, 1, MAX, f); 
    B(buffer);
    return 0;
}

input

     _.,----,._
   .:'        `:.
 .'              `.
.'                `.
:                  :
`    .'`':'`'`/    '
 `.   \  |   /   ,'
   \   \ |  /   /
    `\_..,,.._/'
     {`'-,_`'-}
     {`'-,_`'-}
     {`'-,_`'-}
      `YXXXXY'
        ~^^~

output

╔======================╗
║      _.,----,._      ║
║    .:'        `:.    ║
║  .'              `.  ║
║ .'                `. ║
║ :                  : ║
║ `    .'`':'`'`/    ' ║
║  `.   \  |   /   ,'  ║
║    \   \ |  /   /    ║
║     `\_..,,.._/'     ║
║      {`'-,_`'-}      ║
║      {`'-,_`'-}      ║
║      {`'-,_`'-}      ║
║       `YXXXXY'       ║
║         ~^^~         ║
╚======================╝

C golfing tips appreciated!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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