Write a program that takes as its input a string that outputs a string with the following properties.

  • If a character in the string is an uppercase letter (ASCII 41-5A), then the character is replaced by a string containing every letter up to and including the original letter in upper case. For example, if the input string is I, then the output would be ABCDEFGHI.
  • Similarly, if a character is a lowercase letter (ASCII 61-7A), then the character is replaced in the same way. i would be replaced by abcdefghi.
  • If a character is a number (ASCII 30-39), then the character is replaced by every number starting from 0 and counting up to the number.
  • If the input contains concatenated individual characters, then the replacement sequences are concatenated together.
  • All other characters are printed without modification.

Sample inputs (separated by blank lines)



Hello, World!

Sample outputs



ABCDEFGHabcdeabcdefghijklabcdefghijklabcdefghijklmno, ABCDEFGHIJKLMNOPQRSTUVWabcdefghijklmnoabcdefghijklmnopqrabcdefghijklabcd!

This is code golf, fellas. Standard rules apply. Shortest code in bytes wins.

To see the leaderboard, click "Show code snippet", scroll to the bottom and click "► Run code snippet". Snippet made by Optimizer.

/* Configuration */

var QUESTION_ID = 61940; // Obtain this from the url
// It will be like http://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 43444; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "http://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;

function commentUrl(index, answers) {
  return "http://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;

function getAnswers() {
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answers_hash[id] = a;
      if (!data.has_more) more_answers = false;
      comment_page = 1;

function getComments() {
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();


var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;

function process() {
  var valid = [];
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    var match = body.match(SCORE_REG);
    if (match)
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
    else console.log(body);
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);

    var lang = a.language;
    lang = jQuery('<a>'+lang+'</a>').text();
    languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang, user: a.user, size: a.size, link: a.link};

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))

  langs.sort(function (a, b) {
    if (a.lang_raw.toLowerCase() > b.lang_raw.toLowerCase()) return 1;
    if (a.lang_raw.toLowerCase() < b.lang_raw.toLowerCase()) return -1;
    return 0;

  for (var i = 0; i < langs.length; ++i)
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);

body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;

#language-list {
  padding: 10px;
  width: 290px;
  float: left;

table thead {
  font-weight: bold;

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="language-list">
  <h2>Shortest Solution by Language</h2>
  <table class="language-list">
    <tbody id="languages">

<div id="answer-list">
  <table class="answer-list">
    <tbody id="answers">

<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>
<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>

  • 10
    \$\begingroup\$ Idea for a sequel: undo this transformation. \$\endgroup\$ – ETHproductions Oct 27 '15 at 18:56
  • 2
    \$\begingroup\$ @ETHproductions Perhaps, though the way here seems better to me because it can take any input; what if in the reverse the input were Hello, World!? \$\endgroup\$ – Arcturus Oct 27 '15 at 18:58
  • \$\begingroup\$ Do we have to support NUL (ascii 0x00) characters in the input string? \$\endgroup\$ – nimi Oct 27 '15 at 20:33
  • \$\begingroup\$ @Eridan in such a case, the code should either print an error or, for a fun twist, perform the above transformation. I.e., f(f(input)) == input. I don't believe it is possible for any alphanumerical input to disobey this relation. \$\endgroup\$ – Jake Oct 28 '15 at 1:46
  • 1
    \$\begingroup\$ That is entirely true - I make the assumption that "if a string CAN BE the result of the transformation, reverse it. Otherwise, apply the transformation." - it's your challenge, you can specify any rules you choose so long as (a) they're consistent and (b) they are verifiable and don't require an entire new branch of mathematics to solve. Side note: Irradicating (b) would be interesting; you never know when someone will accidently revolutionise computer science by coming up with a polynomial time algorithm for an NP problem - which is actually reasonable on here, so long as it saves 4 bytes. \$\endgroup\$ – Jake Oct 28 '15 at 2:18

26 Answers 26


Pyth, 19 bytes


Try it online: Demonstration or Test Suite


      rBG1            the list ["abc...xyz", "ABC...XYZ"]
     +    jkUT        appends the string "0123456789"
    J                 save this list of 3 strings in J
   sJ                 join the strings in J
               ._MJ   create all prefixes of the strings in J
              s       and combine them to one list
 XzsJ         s._MJ   translate the input string, chars from sJ
                      get translated to the correct prefix,
                      chars that don't appear in sJ don't get translated
s                     join all resulting translation strings

Python 2.7, 100 98 96 bytes

for c in raw_input():d=ord(c);a+=range(max(d&96|1,48),d)*c.isalnum()+[d]
print bytearray(a)

TeaScript, 24 bytes 26 28

TeaScript is JavaScript for golfing


Pretty short

Try it online


x.l(#            // Loops through each character of the string

     (i=l.N()1)  // Determines whether a character is alphanumeric
                 // Will return A-Z, a-z or 0-9 depending on result
                 // Assigns to variable i

     .h(         // Get characters up to...
        i.i      // where the character is in "i"
     ) + 1       // Increased by one

Ruby, 137 87 82 76 67 55 bytes

Ungolfed, but you can see the pattern.

$><<gets.gsub(/[a-z0-9]/i){[*" 0Aa"[$&.ord/32]..$&]*""}

Edit: golfed down to only one regex.

Edit 2: had a lot of extra spaces.

Edit 3: Thanks to manatwork for golfing 12 bytes!

  • 1
    \$\begingroup\$ $><<gets.gsub(/[a-z0-9]/i){[*" 0Aa"[$&.ord/32]..$&]*""} \$\endgroup\$ – manatwork Oct 28 '15 at 9:21
  • \$\begingroup\$ @manatwork Damn that's clever! \$\endgroup\$ – Peter Lenkefi Oct 28 '15 at 10:33

Haskell, 95 91 86 60 bytes


Usage example: f "pi=3.14159" -> "abcdefghijklmnopabcdefghi=0123.0101234010123450123456789"

How it works: copy every char c in the input string unless c is in-between any of A/Z, a/z or 0/9 and if so take the list of [<first char in pair> ... <c>].

Edit: @Zgarb saved many many bytes. Thanks!

  • \$\begingroup\$ I think you can define c#_=[c] and skip t entirely. \$\endgroup\$ – Zgarb Oct 27 '15 at 20:54
  • \$\begingroup\$ @Zgarb: Yes indeed and then s is also superfluous. Thanks a lot! \$\endgroup\$ – nimi Oct 27 '15 at 21:01

JavaScript (ES6), 143 138 bytes

Uses string comparisons to test which characters to use.


Online demo. Tested in Firefox and Chrome.

Edit: Saved 5 bytes by replacing a='0123456789abcdefghijklmnopqrstuvwxyz' with


Python 2, 145 140 133 103 102 Bytes

A not-so-sleek anonymous function using list comprehension. I feel like the logic should be much shorter, I'll try and figure something out.

lambda k:''.join([c,`map(chr,range(48+17*(c>'@')+32*(c>'`'),ord(c)+1))`[2::5]][c.isalnum()]for c in k)

Should be given a name to be used, i.e. f=...

  • \$\begingroup\$ @Mego Oh, haha! No worries :) \$\endgroup\$ – Kade Oct 27 '15 at 19:50

PHP, 146 bytes


function f($n,&$l){for(;$c=$n[$r],$b=0,$d=ord($c);$r++,$b?:$l.=$c)foreach([58=>48,91=>65,123=>97] as $m=>$i)while($d<$m&&$d>=$i)$b=$l.=chr($i++);}

Revision 1: put ord ranges directly into foreach. incremented ord range maxes and changed $d<=$m to $d<$m. using for to iterate chars instead of foreach and str_split. Removed all {} by moving code into for


function f($input,&$output){
foreach (str_split($input) as $char){
  $ord = ord($char);
  $ords = [57=>48,90=>65,122=>97];
  $b = 0;
  foreach ($ords as $max=>$min){
     while ($ord<=$max&&$ord>=$min){
         $b = $max;
         $output .= chr($min);
  $b ?: $output.=$char;

$output = NULL;
$input = "pi=3.141592";
echo $output;

Explanation: split string into array. If ascii value falls into a range (for a-z,A-Z,0-9), then increment a counter from the min of the range to the char's ascii value, appending each value until you reach the char's ascii value.

I passed in &$var so output is done by reference rather than a return

  • \$\begingroup\$ There is no need for variable $z to hold the array of ranges, you can put the array literal directly in foreach. \$\endgroup\$ – manatwork Oct 28 '15 at 17:29
  • \$\begingroup\$ Tried to use range()? pastebin.com/k2tqFEgD \$\endgroup\$ – manatwork Oct 28 '15 at 17:48
  • \$\begingroup\$ @manatwork, I changed from declaring $z and made some other changes. range() would probably be better. I might try something with range later. \$\endgroup\$ – Reed Oct 28 '15 at 18:16
  • \$\begingroup\$ Using range, I got function f($n,&$l){$o=['a'=>'z','A'=>'Z','0'=>'9'];foreach(str_split($n) as $c){$b=0;foreach($o as $m=>$x)!($c>$m&&$c<=$x)?:$b=$l.=implode(range($m,$c));$b?:$l.=$c;}}, which was 166. \$\endgroup\$ – Reed Oct 29 '15 at 1:11
  • 1
    \$\begingroup\$ Yes, after your rewrite to 146 characters using range() is less beneficial. But that 166 is too long even so: the $o for the array literal is back, there are extra spaces around as keywords, join() is alias for implode(). (Checked the pastebin code I linked earlier? Shows another possibility to store the range endpoints.) Regarding your 146 characters solution, you can move the assignment to $c inside the ord() call: $d=ord($c=$n[$r]). \$\endgroup\$ – manatwork Oct 29 '15 at 9:00

Python, 143 bytes

lambda s:''.join(map(chr,sum(map(lambda a,r=range:r(65,a+1)if 64<a<97else r(97,a+1)if 96<a<123else r(48,a+1)if 47<a<58else[a],map(ord,s)),[])))

Try it online

  • 2
    \$\begingroup\$ You could use z=range to save 4 bytes. \$\endgroup\$ – Arcturus Oct 27 '15 at 19:19
  • 1
    \$\begingroup\$ Pretty sure that you can replace the double space indents with a single tab, which would save you a few bytes \$\endgroup\$ – Fund Monica's Lawsuit Oct 27 '15 at 19:25

Perl 6, 101 bytes

Here is a first pass at it:

sub MAIN($_ is copy){
sub MAIN($_ is copy){s:g/<[0..9]>/{(0..$/).join}/;s:g/<[a..z]>/{('a'..~$/).join}/;s:g/<[A..Z]>/{('A'..~$/).join}/;.say}


Using .trans on $_to remove is copy.

sub MAIN($_){
    /\d/       => {(0..$/).join},
    /<[a..z]>/ => {('a'..~$/).join},
    /<[A..Z]>/ => {('A'..~$/).join}
sub MAIN($_){.trans(/\d/=>{(0..$/).join},/<[a..z]>/=>{('a'..~$/).join},/<[A..Z]>/=>{('A'..~$/).join}).say}


Act on @*ARGS directly instead of defining a MAIN sub.
(otherwise identical to previous example)




Scala, 111 91 bytes

val f=(_:String).flatMap(x=>if(x.isDigit)('0'to x)else if(x.isUpper)('A'to x)else('a'to x))
  • \$\begingroup\$ This fails for pi=3.14159. Could the solution be val f=(_:String).flatMap(x:String=>if(x.isDigit)('0'to x)else if(x.isUpper)('A'to x)else if(x.isLower)('a'to x)else x.toString) for a whopping 128 characters? \$\endgroup\$ – Leonardo Oct 28 '15 at 11:28

Julia, 102 98 90 84 bytes

s->join([(i=Int(c);join(map(Char,(64<c<91?65:96<c<123?97:47<c<58?48:i):i)))for c=s])

This creates an unnamed function that accepts a string and returns a string.


function f(s::AbstractString)
    # For each character in the input, get the codepoint and construct
    # a range of codepoints from the appropriate starting character to
    # the current character, convert these to characters, and join them
    # into a string
    x = [(i = Int(c);
          join(map(Char, (isupper(c) ? 65 :
                          islower(c) ? 97 :
                          isdigit(c) ? 48 : i):i))
         ) for c in s]

    # Join the array of strings into a single string
    return join(x)

PowerShell, 155 Bytes


Technically a one-liner, and PowerShell is all about those ;-)

Splits the input, pipes that into a ForEach-Object loop, switches on the integer value of the cast character, then generates new char[] of the appropriate ranges. Note that we have to spend bytes to set a temp variable $b because the act of casting the input $_ in the switch statement means that we can't just keep using $_ or we'll get funky output.

EDIT - I should point out that this will toss off errors since the first object being fed into %{...} is a null object. Since STDERR is ignored by default, this shouldn't be an issue. If it's a problem, change the first bit to be ($args-split''-ne''|... to eliminate the null object.


JavaScript (ES6), 340 258 273 271 bytes

a=s=>{s=s.split``;Q=x=>x.toUpperCase();A="ABCDEFGHIJKLMNOPQRSTUVWXYZ";D="0123456789";f="";for(i=0;i<s.length;i++){j=s[i];c="to"+(Q(j)==j?"Upper":"Lower")+"Case";j=Q(j);if(q=A.search(j)+1)f+=g=A.slice(0,q)[c]();else if(q=D.search(j)+1)f+=g=D.slice(0,q);else f+=j}return f}
  • \$\begingroup\$ You can use a template string `` for split instead of ("") and f=i="" in the for loop. You might be able to save a few more bytes. \$\endgroup\$ – intrepidcoder Oct 27 '15 at 21:07
  • \$\begingroup\$ @intrepidcoder The first would work. I'm checking on the second. \$\endgroup\$ – Conor O'Brien Oct 27 '15 at 21:35

C (269 bytes)

(line break added for clarity)

#define F(x,y,z)if(c>=T[0][x]&&c<=T[1][y]){z}
#define L(x,y)for(i=0;i<x;++i){y}
main(){int c,i,n;char o,*T[]={"0Aa","9Zz"};while((c=getchar())!=EOF)
{F(0,2,L(3,F(i,i,o=T[0][i],n=++c-o;L(n,putchar(o++));break;))else putchar(c);)}}


int main(void)
  int c, i, n;
  char output;
  char *char_table[] = {"0Aa", "9Zz"};

  while ((c = getchar()) != EOF) {
    if (c < '0' || c > 'z') {
    } else {
      for (i = 0; i < 3; ++i) {
        if (c >= char_table[0][i] && c <= char_table[1][i]) {
          output = char_table[0][1];
          n = c - output;
      for (i = 0; i <= n; ++i) {

Perl 5, 66 61 (51 Bytes + 1) 52

Combining regexes with conditional operators worked out nice in this case.
With a join Using map to combine the ranges into an array.

say map{(/\d/?0:/[A-Z]/?A:/[a-z]/?a:$_)..$_}split//


$ echo "A0C1.a3c_2!" |perl -M5.010 -n count_and_spell_up.pl


say                # print output
  map{             # loop through the array that's at the end of the other mustache. 
                   # outputs an array. 
        /\d/?0            # if $_ is a digit then 0
          :/[A-Z]/?A      # else, if it's an uppercase character then A
             :/[a-z]/?a   # else, if it's a lowercase character then a
               :$_        # else the current character
     )..$_         # generate a sequenced string of characters 
                   # that ends with the magic variable $_ 
                   # ($_ is currently a character from the array)
  }split//     # split the magic variable $_ (currently the input string)
               # to an array of characters

JavaScript (ES7), 125 bytes

There were already two JS answers focusing on encoding the strings, so I decided to go for a more algorithmic approach using String.fromCharCode():

x=>x.replace(/[^\W_]/g,z=>(c=z.charCodeAt(),f=c<65?48:c<97?65:97,String.fromCharCode(...[for(i of Array(c-f).keys())i+f])+z))

A bonus of using this method is that it takes any amount of char codes, so joining the list is not necessary. This turned out shorter than any other technique, so I'm happy with the result.


MUMPS, 131 bytes

u(l,h) i l'>a,a'>h f j=l:1:a s o=o_$C(j),f=0
t(s) f i=1:1:$L(s) s a=$A(s,i),f=1 d u(48,57),u(65,90),u(97,122) s:f o=o_$C(a)
    q o

I did manage to save a good few bytes here thanks to MUMPS's dynamic scoping. Here's a roughly-equivalent ungolfed version, which I sure would love to syntax highlight, if only support for the MUMPS Prettify module were available.

convert(str) ;
    new asciiCode,flag,i,output
    for i=1:1:$LENGTH(str) do
    . set asciiCode=$ASCII(str,i)
    . set flag=1
    . do helper(48,57)
    . do helper(65,90)
    . do helper(97,122)
    . if 'flag do
    . . set output=output_$CHAR(asciiCode)
helper(low,high) ;
    if low'>asciiCode,asciiCode'>high do
    . for code=low:1:asciiCode do
    . . set output=output_$CHAR(code)
    . . set flag=0

Perl 6, 78 77 bytes

@*ARGS[0].trans(/\d/=>{[~] 0..$/},/<:L>/=>{[~] samecase("a",~$/)..~$/}).say
  • \$\begingroup\$ I knew it could be shortened by combining the 'a'..'z' and 'A'..'Z' cases, I should have tried harder. \$\endgroup\$ – Brad Gilbert b2gills Nov 1 '15 at 18:00
  • \$\begingroup\$ I recommend adding <!-- language-all: lang-perl6 --> just after ## Perl 6 so that it will highlight correctly. ( Change is already pending on this answer ) \$\endgroup\$ – Brad Gilbert b2gills Nov 1 '15 at 18:03
  • \$\begingroup\$ You can switch {[~](0..$/)} to {[~] 0..$/} which will save one byte. \$\endgroup\$ – Brad Gilbert b2gills Nov 3 '15 at 18:36

Mathematica, 102 bytes


Oh well...


CJam, 32 31 bytes


Try it online in the CJam interpreter.

How it works

q_    e# Push two copies of the user input.
'[,   e# Push the string of all ASCII characters up to Z.
_el   e# Push a copy and convert it to lowercase.
^     e# Perform symmetric difference this keeps only letters.
A,s+  e# Append the string "0123456789".
26/   e# Split the result into chunks of length 26.
ff{   e# For each character from input: For each chunk:
  _@  e#   Copy the chunk and rotate the character on top of it.
  #   e#   Push the index of the character in the string (-1 for not found).
  )<  e#   Increment and keep that many characters from the left of the chunk.
      e#   This pushes "" for index -1.
:s    e# Flatten the resulting arrays of strings.
      e# The results will be empty strings iff the character wan't alphanumeric.
\     e# Swap the result with the input string.
.e|   e# Perform vectorized logical OR.

Python 2, 135 117 bytes

for c in raw_input():
 if c.isalnum():
 for i in range(b,e):s+=chr(i)
print s

PHP - 291 bytes

Pass the string to GET["s"].

<?php $s=$_GET["s"];$m="array_map";echo implode($m(function($v){$i="in_array";$l="implode";$r="range";global$m;$a=ord($v);if($i($a,$r(48,57)))$v=$l($m("chr",$r(48,$a)));if($i($a,$r(65,90)))$v=$l($m("chr",$r(65,$a)));if($i($a,$r(97,122)))$v=$l($m("chr",$r(97,$a)));return$v;},str_split($s)));

C#, 251 201 184 157 154 Bytes

using System;class c{static void Main(string[] i){foreach(var c in i[0])for(var x=c>64&c<91?'A':c>96&c<123?'a':c>47&c<58?'0':c;x<=c;)Console.Write(x++);}}

edit: Strike! Shorter than PowerShell ;)

  • 1
    \$\begingroup\$ can you do string[]i? \$\endgroup\$ – Erik the Outgolfer Jun 15 '16 at 14:29

APL (Dyalog Extended), 37 bytes


Try it online!

A train that accepts a string as right argument.


05AB1E, 9 bytes


Try it online.


žK         # Push "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  D        # Duplicate it
   ₂ô      # Split the copy into parts of size 26: ["abc...xyz","ABC...XYZ","012...789"]
     €     # Map over each inner string:
      η    #  Get a list of its prefixes
       ˜   # Flatten this list of lists of strings
           #  ["a","ab","abc",...,"A","AB","ABC",...,"0","01","012",...,"0123456789"]
        ‡  # Transliterate all characters in the (implicit) input-string from 
           # "abc...xyzABC...XYZ012...789" to these prefixes at the same positions
           # (after which the result is output implicitly)

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.