# Convert exponents into ASCII art

abc^d+ef^g + hijk^l - M^NO^P (Ag^+)


To strings like this:

   d   g       l    N P    +
abc +ef  + hijk  - M O  (Ag )


Which is an approximation to abcd+efg + hijkl - MNOP (Ag+)

In words, raise the characters directly next to carets to the upper line, one character for one caret.

# Specs

• Extra trailing whitespaces in the output are allowed.
• No chained carets like m^n^o will be given as input.
• A caret will not be followed immediately by a space or by another caret.
• A caret will not be preceded immediately by a space.
• All carets will be preceded by at least one character and followed by at least one character.
• The input string will only contain printable ASCII characters (U+0020 - U+007E)
• Instead of two lines of output, you are allowed to output an array of two strings.

To those who speak regex: the input string will match this regex:

/^(?!.*(\^.\^|\^\^|\^ | \^))(?!\^)[ -~]*(?<!\^)/  ### Leaderboard var QUESTION_ID=86647,OVERRIDE_USER=48934;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i; body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px} <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> • @TimmyD "The input string will only contain printable ASCII characters (U+0020 - U+007E)" – Leaky Nun Jul 26 '16 at 21:01 • Why stop at exponents? I want something that handles H_2O! – Neil Jul 26 '16 at 22:38 • @Neil Make your own challenge then, and I may close this challenge as a duplicate of that one. :) – Leaky Nun Jul 26 '16 at 22:39 • Based on your example I'd say they are superindices, not necessarily exponents – Luis Mendo Jul 26 '16 at 22:45 • Those who speak regex hail from a highly regular country where expression is tightly constrained. The leading cause of death is catastrophic backtracking. – David Conrad Jul 27 '16 at 8:28 ## 22 Answers # V, 15 14 bytes ÄÒ +òf^xxé kPj  Try it online! A fairly straightforward solution. The perfect challenge for V! Explanation: Ä "Duplicate this current line Ò "Replace this line with spaces + "Move to the beginning of the next line ò ò "Recursively (The second ò is implicit): f^ " Find a caret xx " Delete two characters. The second will be saved into the main register é " Insert a space k " Move up P " Paste from the main register j " Move down  Conveniently, based on how the recursion works, this will run once for every single caret. • vim is perfect language for this challenge. +1 – Downgoat Jul 26 '16 at 23:58 # Cheddar, 7772 67 bytes l->l.chars.vfuse.replace("^\n"," ").lines.map(j->"%-2s"%j).turn(3)  No regex! I love this answer as it is a wonderful demonstration of Cheddar's abilities. Mainly thanks to the replace function added by Conor. The PR to dev was never made so the replace function only exists on this branch (update: I made the PR and now it's on the latest beta branch which you can install with npm install -g cheddar-lang) I have found a way to golf it but unfortunately an oversight results in this happening when item lengths are not the same: [" denifednud denifednug denifednul denifednuN denifednuP denifednu+ ", "abcdenifednu +efdenifednu + hijkdenifednu - Mdenifednu Odenifednu (Agdenifednu )"]  I could have saved a lot of bytes using regex, and in fact I just made regexes for Cheddar... the only problem is that there are no regex functions :/ ## Explanation l-> // Function take input as l l.chars // Get array of chars in input .vfuse // Join with newlines .replace("^\n"," ") // Replace ^\n with a space globally .lines // Get the lines (see below for more details on what this returns) .map(j-> // Loop through each "line" j is arg "%-2s" // C-like printf format. // think of as: padRight(j, " ", 2) // see below for more details % j // Pass j as the string to insert ).turn(3) // Turn the string 270 degrees (see below) .vfuse // Vertically fuse to get result (this is not needed as we can output an array of the lines)  To get a better understanding. This is what .lines returns for 1^2 ["1", " 2"]  the .turn with rotate this: 1 2  into:  2 1  Another example which will make it more clear: 1 2 2 2  becomes:  2 2 1 2  ### Why format? What the %-2s is doing is pretty simple. % specifies we are starting a "format", or that a variable will be inserted into this string at this point. - means to right-pad the string, and 2 is the max-length. By default it pads with spaces. s just specifies it's a string. To see what it does: "%-2s" % "a" == "a " "%-2s" % " a" == " a"  • :D I always upvote cheddar. – James Jul 26 '16 at 23:23 • @DrGreenEggsandIronMan :D thank you – Downgoat Jul 26 '16 at 23:30 • Cheddar have a turn method for strings? – TuxCrafting Jul 27 '16 at 9:29 • -1 this language's name always makes me hungry. – ceased to turn counterclockwis Jul 27 '16 at 10:01 • @TùxCräftîñg only for 2D arrays, which is why i used .lines to get the lines. – Downgoat Jul 27 '16 at 17:36 # Perl, 21 + 1 = 22 bytes say'';s/\^(.)/♥[A\1↓/  Run with the -p flag. Replace ♥ with a raw ESC byte (0x1b), and ↓ with a vertical tab (0x0b). The vertical tab is Martin Ender’s idea. It saved two bytes! Thanks. • Wouldn't you need to move the cursor down a line at the start so that the exponents don't overlap the last console prompt? – Martin Ender Jul 26 '16 at 22:58 • I wasn't sure about that, yeah. I made the assumption of having as much space as I need, but maybe that’s a bit cheaty. (In general, I’m not very proud of using cursor movements to solve this kind of problem, but it’s the first thing that came to mind...) – Lynn Jul 26 '16 at 23:03 • I think it's a fine solution but the result should be visually indistinguishable from printing the string as intended. – Martin Ender Jul 26 '16 at 23:11 • What a lovely solution – Thomas Weller Jul 28 '16 at 7:37 ## JavaScript (ES6), 56 55 bytes s=>[/.(\^(.))?/g,/\^.(())/g].map(r=>s.replace(r,'2'))


Regexps to the rescue of course. The first one replaces all characters with spaces, unless it finds a caret, in which case it deletes the caret and keeps the character after it. (These characters are guaranteed to exist.) The second is the obvious one to replace each caret and its following character with a space.

Edit: Saved 1 byte thanks to @Lynn who devised a way to reuse the replacement string for the second replace allowing the replace to be mapped over an array of regexps.

• @DomHastings regardless of if it works or not, your code doesn't seem to have a newline, and adding +$/ means it's not going to save bytes. puts throws in the newline for you automatically when the , is present between arguments. – Value Ink Jul 27 '16 at 17:42 • Oh... I tested using ruby -p ... <<< 'input' but I agree, if it's missing the newline it's no good! Actually, I might have had a newline appended in my tests earlier... It was at work though so I can't check! – Dom Hastings Jul 27 '16 at 18:59 • @DomHastings Looking at it again, my guess is that it's because gets includes the trailing newline most of the time, but if you pipe in a file that doesn't contain the trailing newline, then it won't appear and the output will be wrong. Test your code with ruby -p ... inputfile since Ruby redirects the gets to the file if it's a command line argument. – Value Ink Jul 28 '16 at 8:10 • Got it, makes perfect sense. I guess a trailing newline in the file would also fix the problem. I'm not a proficient Rubyist by any means so I feel like I've learnt a little more about it today. Thanks! – Dom Hastings Jul 28 '16 at 10:25 # Python (2), 7668 67 Bytes -5 Bytes thanks to @LeakyNun -3 Bytes thanks to @KevinLau-notKenny -1 Byte thanks to @ValueInk -0 bytes thanks to @DrGreenEggsandIronMan import re lambda i,s=re.sub:[s("(?<!\^).\^?"," ",i),s("\^."," ",i)]  This anonymous Lambda function takes the input string as its only argument and returns the two output lines separated by a newline. To call it give it a name by writing "f=" before it. Pretty straightforward regex: The first part replaces the following by a space: any character and a carrot caret or only a char, but only if there is no caret before them. The second part replaces any caret in the string and the char after it by a space. • @LeakyNun: I was for some reason wondering if 1. also holds if i import libraries. Was copying 2. into this question right now when i saw your comment. Thanks to you and Kevin! – KarlKastor Jul 26 '16 at 22:49 • You could take one byte off with from re import* – James Jul 27 '16 at 6:55 • @DrGreenEggsandIronMan This seems to use exactly the same numer of bytes. (see above) – KarlKastor Jul 27 '16 at 8:28 • Keep the old import statement and do lambda i,s=re.sub:[s("(?<!\^).\^?"," ",i),s("\^."," ",i)] for -1 byte – Value Ink Jul 27 '16 at 18:14 ## Convex, 24 bytes ®(?<!\^).\^?"SòNê®\^."Sò  Try it online! # Retina, 16 bytes S^ \^(.) ♥[A$1↓


A port of my Perl answer, pointed out by Martin Ender. Replace ♥ by a raw ESC byte (0x1b) and ↓ with a vertical tab (0x0b).

# shell+TeX+catdvi, 51 43 bytes

tex '\empty$'$1'$\end'>n;catdvi *i|head -n2  Uses tex to typeset some beautiful mathematics, and then uses catdvi to make a text representation. The head command removes junk (page numbering, trailing newlines) that is otherwise present. Edit: Why do the long, proper, thing and redirect to /dev/null when you can ignore sideeffects and write to a single letter file? ## Example Input: abc^d+ef^g + hijk^l - M^NO^P (Ag^+) TeX output (cropped to equation): Final output:  d g l N P + abc +ef +hijk -M O (Ag )  Assumptions: Start in empty dir (or specifically a dir with no name ending in "i"). Input is a single argument to the shell script. Input is not an empty string. Someone tell me if this is rule abuse, especially catdvi. ## Haskell, 7456 55 bytes g('^':c:r)=(c,' '):g r g(c:r)=(' ',c):g r g x=x unzip.g  Returns a pair of strings. Usage example: unzip.g$ "abc^d+e:qf^g + hijk^l - M^NO^P: (Ag^+)" -> (" d g l N P + ","abc +e:qf + hijk - M O : (Ag )")

g makes a list of pairs, where the first element is the char in the upper line and the second element is the char in the lower line. unzip turns it into a pair of lists.

Edit: @xnor suggested unzip which saves 18 bytes. @Laikoni found one more byte to save. Thanks!

• Can you do j=unzip.g? – xnor Jul 28 '16 at 0:53
• @xnor: oh, how stupid of me not to see that myself! Thanks a lot! – nimi Jul 28 '16 at 4:48
• You can replace g[]=[] with g x=x to save one byte. – Laikoni Aug 18 '16 at 12:26
• @Laikoni: Well spotted! Thanks! – nimi Aug 18 '16 at 18:08

## Perl, 35 bytes

34 bytes code + 1 for -p

$_=s/\^(.)|./$1||$"/ger.s/\^./ /gr  ### Usage perl -pe '$_=s/\^(.)|./$1||$"/ger.s/\^./ /gr' <<< 'abc^d+ef^g + hijk^l - M^NO^P (Ag^+)'
d   g       l    N P    +
abc +ef  + hijk  - M O  (Ag )


Note: This is exactly the same as Value Ink's answer which I spied afterwards. Will remove if needed as this doesn't really add to the Ruby solution.

## Java 8 lambda, 132128 112 characters

i->{String[]r={"",""};for(char j=0,c;j<i.length();j++){c=i[j];r[0]+=c==94?i[++j]:32;r[1]+=c==94?32:c;}return r;}


The ungolfed version looks like this:

public class Q86647 {

static String[] printExponents(char[] input) {
String[] result = {"",""};
for (char j = 0, c; j < input.length(); j++) {
c = input[j];
result[0] += c == 94 ? input[++j] : 32;
result[1] += c == 94 ? 32 : c;
}
return result;
}
}


Outputs as an array, simply checking whether there is a caret and if so the next character will be put in the upper row, else there will be a space.

Replaced characters with their ascii values to save 4 characters.

Thanks to @LeakyLun for pointing out to use a char array as input instead.

Also thanks to @KevinCruijssen for switching the int to char to save some more characters.

• You can try to input char[] and use for(char c:i) to see if the byte-count can be reduced. – Leaky Nun Jul 28 '16 at 1:13
• You can golf it down a bit to 110 bytes by using: i->{String[]r={"",""};for(char j=0,c;j<i.length;j++){c=i[j];r[0]+=c==94?i[++j]:32;r[1]+=c==94?32:c;}return r;} with "abc^d+ef^g + hijk^l - M^NO^P (Ag^+)".toCharArray() as input. (Ideone of these changes.) – Kevin Cruijssen Jul 28 '16 at 9:38

# Coconut, 122 114 96 bytes

Edit: 8 26 bytes down with help from Leaky Nun.

def e(s,l)=''==l and s or"^"==l[0]and l[1]+e(s+' ',l[2:])or' '+e(s+l[0],l[1:])
f=print..e$('\n')  So as I learned today python has a ternary conditional operator, or in fact two of them: <true_expr> if <condition> else <false_expr> and <condition> and <true_expr> or <false_expr> with last one coming with one char less. A python conform version can be ideoned. First attempt: def e(s,l): case l: match['^',c]+r:return c+e(s+' ',r) match[c]+r:return' '+e(s+c,r) else:return s f=print..e$('\n')


Calling with f("abc^d+ef^g + hijk^l - M^NO^P (Ag^+)") prints

   d   g       l    N P    +
abc +ef  + hijk  - M O  (Ag )


Anyone tried golfing in coconut yet? It enriches python with more functional programming concepts like the pattern matching and function concatenation (with ..) used above. As this is my first try at coconut, any tips would be appreciated.

This could definitely be shortened as any valid python code is also valid coconut and shorter python answers have been posted, however I tried to find a purely functional solution.

• I think you can use ternary operators (x and y or z) to replace the case. – Leaky Nun Jul 28 '16 at 9:38
• You can even use s[0]=="^" instead of match['^',c]+r in l – Leaky Nun Jul 28 '16 at 9:40
• @LeakyNun When I replace match['^',c]+r with s[0]=="^", then c and r are no longer bound. How would this help? – Laikoni Jul 28 '16 at 9:45
• You can use s[1] to replace c and s[2:] to replace r. – Leaky Nun Jul 28 '16 at 10:02
• then you can use ternary now. – Leaky Nun Jul 28 '16 at 15:41

## Dyalog APL, 34 bytes

{(0 1=⊂b/¯1⌽b){⍺\⍺/⍵}¨⊂⍵/⍨b←⍵≠'∧'}


It returns a two-element vector with the two lines

Sample run (the uparrow in front is to format the two-el. vector for human consumption):

      ↑{(0 1=⊂b/¯1⌽b){⍺\⍺/⍵}¨⊂⍵/⍨b←⍵≠'∧'}'abc∧d+ef∧g + hijk∧l - M∧NO∧P (Ag∧+)'
d   g       l    N P    +
abc +ef  + hijk  - M O  (Ag )

• To your comment on my question about code doing nothing: yes, that code you put counts. – haykam Jul 27 '16 at 21:59

## PowerShell v2+, 88 83 bytes

-join([char[]]$args[0]|%{if($c){$_;$b+=' '}elseif($_-94){$b+=$_;' '}$c=$_-eq94});$b


A little longer than the others, but showcases a little PowerShell magic and a little different logic.

Essentially the same concept as the Python answers -- we iterate over the input character-by-character, remember whether the previous one was a caret ($c), and put the current character into the appropriate spot. However, the logic and method for determining where to output is handled a little differently, and without a tuple or separate variables -- we test if the previous character was a caret, and if so output the character to the pipeline and concatenate a space onto $b. Otherwise we check if the current character is a caret elseif($_-94) and so long as it's not, we concatenate the current character onto $b and output a space to the pipeline. Finally, we set whether the current character is a caret for the next go-round.

We gather those characters from the pipeline together in parens, encapsulate them in a -join which turns them into a string, and leave that along with $b on the pipeline. Output at the end is implicit with a newline inbetween. For comparison, here's a direct port of @xnor's Python answer, at 85 bytes: $a=,''*2;[char[]]$args[($l=0)]|%{$a[!$l]+="$_"*($c=$_-ne94);$a[$l]+=' '*$c;$l=!$c};$a  # Gema, 42 41 characters \^?=?@set{s;$s }
?=\ @append{s;?}
\Z=\n$s  Gema processes input as stream, so you have to solve it in one pass: first line is written immediately as processed, second line is collected in variable$s, then output at the end.

Sample run:

bash-4.3$gema '\^?=?@set{s;$s };?=\ @append{s;?};\Z=\n$s' <<< 'abc^d+ef^g + hijk^l - M^NO^P (Ag^+)' d g l N P + abc +ef + hijk - M O (Ag )  # Cinnamon Gum, 21 bytes 0000000: 5306 6533 bd92 d1db 8899 8381 a2f8 8f8c S.e3............ 0000010: 1230 249e a1 .0$..


Non-competing. Try it online.

## Explanation

I'm not much of a regex golfer so there's probably a better way to do this.

The string decompresses to:

S(?<!\^)[^^]& &\^&S\^.&


(note the trailing space)

The first S stage receives input and uses a negative lookbehind to replace all characters other than carets with no preceding caret with a space, then deletes all carets. Then it immediately outputs the modified input string with a newline and removes that S stage. Since STDIN is now exhausted and the previous stage didn't provide any input, the next S stage receives the last line of STDIN again and then replaces all carets followed by any character with a space and outputs that.

In Perl psuedo-code:

$first_stage_sub_1 = ($input =~ s/(?<!\^)[^^]/ /gr);
$first_stage_sub_2 = ($first_stage_sub_1 =~ s/\^//gr);
print $first_stage_sub_2, "\n";$second_stage_sub = ($input =~ s/\^./ /gr); print$second_stage_sub, "\n";


# J, 28 27 bytes

0|:t#]{."0~_1-_1|.t=.'^'~:]


Try it online!

                  t=.'^'~:]    0 for ^, 1 for the rest, define t
_1|.             Shift right, now zeroes are for superscripts
]{."0~_1-                 Prepend that many spaces to each character
t#                          Remove the rows with carets
0|:                            Transpose


There must be a better way...