Read infinitely from stdin, and convert every number to the corresponding symbol on a US qwerty keyboard.

No string or character literals anywhere are permitted.

E.g. if the input is 117758326, the output is !!&&%*#@^.

Letters and symbols that aren't on numbers are left alone; 11g2;;'1g2311hh21930 turns into !!g@;;'!g@#!!hh@!(#)

Shortest code, in bytes, wins.

For those who don't have a US qwerty keyboard, use the following as a guide:

1 -> !
2 -> @
3 -> #
4 -> $
5 -> %
6 -> ^
7 -> &
8 -> *
9 -> (
0 -> )

12 Answers 12


C, 90 bytes

The line between a character and an integer literal is a very fine one in C.

  • \$\begingroup\$ shoot, there's a string literal in the printf. fixing later \$\endgroup\$ Commented Jul 25, 2014 at 22:19
  • \$\begingroup\$ putchar() - and its 4 bytes shorter too! \$\endgroup\$ Commented Jul 25, 2014 at 22:54
  • 1
    \$\begingroup\$ this is 92 a[]={41,33,64,35,36,37,94,39,42,40};main(d){for(;d=getchar();)putchar(d>47&d<58?a[d-48]:d);} \$\endgroup\$
    – bebe
    Commented Jul 25, 2014 at 23:18
  • 1
    \$\begingroup\$ @DigitalTrauma yeah I know, I just didn't think of it right away for some reason and had to leave really quickly then \$\endgroup\$ Commented Jul 25, 2014 at 23:58
  • 1
    \$\begingroup\$ a[]={8,0,31,2,3,4,61,5,9,7};main(d){for(;d=getchar();)putchar(d>47&d<58‌​?a[d-48]+33:d);} \$\endgroup\$
    – millinon
    Commented Jul 26, 2014 at 0:11

Perl - 74 57 42

Update thanks to core1024's comment:

s/\d/chr 33+(8,0,31,2..4,61,5,9,7)[$&]/eg

Run with:

perl -p program_name.pl

Update thanks to manatwork's comment:

say s/\d/chr@{[8,0,31,2,3,4,61,5,9,7]}[$&]+33/erg while<>

Test with:

perl -E 'say s/\d/chr@{[8,0,31,2,3,4,61,5,9,7]}[$&]+33/erg while<>'

Old attempts:

say s/[1234567890]/chr qw(41 33 64 35 36 37 94 38 42 40)[$&]/erg while(<>)

Using qw counts as a string literal though.


perl -E 'say s/[1234567890]/chr qw(41 33 64 35 36 37 94 38 42 40)[$&]/erg while(<>)'

Another way: Perl 40 - I think this counts as a string literal as well.

say tr/1234567890/!@#$%^&*()/r while(<>)

Test with:

perl -E 'say tr/1234567890/!@#$%^&*()/r while(<>)'
  • \$\begingroup\$ Are you sure that isn't a string literal? !@#$%^&*() sure looks like one. \$\endgroup\$
    – isaacg
    Commented Jul 25, 2014 at 23:01
  • \$\begingroup\$ @isaacg I didn't read the question closely enough and I think you're right. I updated with another solution. \$\endgroup\$
    – hmatt1
    Commented Jul 25, 2014 at 23:45
  • \$\begingroup\$ As documentation describes qw// as “quote a list of words”, in my interpretation there you have 10 string literals. So I suggest to change it into array of integers (@{[41,33,…]} or something better) (no change in code size); leave off the parenthesis around the statement modifier's expression (2 characters shorter); subtract 33 from all character codes and add it separately (3 characters shorter); replace character class with \d wildcard (10 characters shorter): say s/\d/chr(@{[8,0,31,2,3,4,61,5,9,7]}[$&]+33)/erg while<>. \$\endgroup\$
    – manatwork
    Commented Jul 29, 2014 at 13:36
  • \$\begingroup\$ @manatwork thanks! nice work! I updated the answer. Also you can take the parenthesis out of chr(...). \$\endgroup\$
    – hmatt1
    Commented Jul 29, 2014 at 14:17
  • 1
    \$\begingroup\$ You can use the -p flag to drop the while, say and the r RegEx modifier from your code. You can also save more bytes by using 33+(31,2..4,61)[] instead of @{[31,2,3,4,61]}[]+33. \$\endgroup\$
    – core1024
    Commented Jul 31, 2014 at 8:08

JavaScript (ES6) - 79 76 87

Edit - bloated out by 11 chars after it was pointed out that it failed the "non-numbers are left alone" rule (thanks @soktinpk)

Warning - you'll need to reload your browser after you run it since it's following the "Read infinitely from stdin" bit...


Note that I've interpreted prompt as stdin & alert as stdout

Tested in Firefox console.

  • \$\begingroup\$ Wouldn't you have to iterate over it? The input is not guaranteed to be one digit... \$\endgroup\$
    – soktinpk
    Commented Jul 31, 2014 at 0:00
  • \$\begingroup\$ Also, this doesn't satisfy the rule characters which aren't digits should be left alone. \$\endgroup\$
    – soktinpk
    Commented Jul 31, 2014 at 0:07
  • \$\begingroup\$ @soktinpk - on your first point, it loops indefinitely by recursively calling itself (it's an interpretation of how to indefinitely read from stdin in javascript... the implication of the question is that it should process each character as it comes in, which is effectively what I'm doing, via a prompt). Your second point is spot on though, I missed that... will have to revisit the code... \$\endgroup\$
    – Alconja
    Commented Jul 31, 2014 at 0:29
  • \$\begingroup\$ @soktinpk - fixed now - but it cost me 11 characters. Curse you! :P \$\endgroup\$
    – Alconja
    Commented Jul 31, 2014 at 0:48

Pyth, 43

W1sm?C+33@[8Z31 2 3 4 61 5tT7)vd}Cdr48 58dw

Uses 33+table lookup, instead of straight table lookup. No translate function here, just a normal map. Note that Z=0 and tT=9.


Scala, 106 bytes

def f{println(readLine.map{c=>try{(Seq(8,0,31,2,3,4,61,5,9,7)(c.toInt-48)+33).toChar}catch{case _=>c}});f}


def f {
  println(readLine.map { c =>
    try {
      (Seq(8,0,31,2,3,4,61,5,9,7)(c.toInt - 48) + 33).toChar
    } catch {
      case _ => c

pyg-i (68)

Here is a solution in pyg-i, a fork of pyg I created:

while 1:P(Ip().t(dict(Z(R(48,58),(41,33,64,35,36,37,94,38,42,40)))))

The python 3 equivalent would be this:

while 1:print(input().translate(dict(zip(range(48,58),(41,33,64,35,36,37,94,38,42,40)))))

Or, with a little cheating, it can be done in 50 bytes. Note that this is a bytes literal, not a string literal:

while 1:P(Ip().t(dict(Z(R(48,58),b"(!@#$%^&*("))))

CoffeeScript (70)

Update: This may be seen as reading between the lines, but while strings and characters aren't allowed, regexs are. (I just converted the regex to a string).

alert prompt().replace /\d/g, (t)->([]+/!@#$%^&*()/)[1...-1][(+t+9)%10]

Or (for infinite)

loop alert prompt().replace /\d/g, (t)->([]+/!@#$%^&*()/)[1...-1][(+t+9)%10]

The normal version (in case regex isn't allowed):

alert prompt().replace(/\d/g, (t) ->String.fromCharCode(([]+4133643536+3794384240).match(/\d{2}/g)[t]))

Test it out here.

But, according to the problem statement,

Read infinitely from stdin

That will probably hang your browser eventually, but here it is (just prepend loop, extra 5 bytes, to the code):

loop alert prompt().replace(/\d/g, (t) ->String.fromCharCode(([]+4133643536+3794384240).match(/\d{2}/g)[t]))
  • 2
    \$\begingroup\$ Looks like you used a string literal. \$\endgroup\$
    – isaacg
    Commented Jul 25, 2014 at 23:39
  • \$\begingroup\$ @isaacg Updated, sorry. \$\endgroup\$
    – soktinpk
    Commented Jul 25, 2014 at 23:54

Befunge 98 - 119 bytes

This is also with the STRN fingerprint, that allows "S" to stand for a convert integer to string instruction.

v>0 NRTS 4( >&S v         >$a,v
5 )!@#$%^&*(    >:1       w1  v
7^       p<     ^,g1--3*77< 
>*1-:30p80^ ^                 <

Haskell, 89

f 50=64
f 54=94
f 55=38
f 56=42
f 57=40
f 48=41
f x|x<48||x>57=x|0<1=x-16


Prelude> g "11g2;;'1g2311hh21930"


Prelude> g "117758326"



CJam - 32

qA,s26063649909601297730 95b:cer

Try it at http://cjam.aditsu.net/


q reads the whole input
A, creates the array [0 1 ... 9] (A=10)
s converts to string, obtaining "0123456789"
95b converts the previous big number to an array of base-95 digits, which are the ASCII codes of the 10 symbols we want
:c converts the ASCII codes to characters, obtaining the string ")!@#$%^&*("
er transliterates "0123456789" to ")!@#$%^&*(" in the input string


tcl, 156

proc x n {format %c $n}
while 1 {puts [string map "1 [x 33] 2 [x 64] 3 [x 35] 4 [x 36] 5 [x 37] 6 [x 94] 7 [x 38] 8 [x 36] 9 [x 40] 0 [x 41]" [gets stdin]]}

testable on http://www.tutorialspoint.com/execute_tcl_online.php?PID=0Bw_CjBb95KQMRE4tMlc3cmJhNG8


PYTHON: 166 86

Not better than the current answers, but the shortest Python solution I can think of as of yet.

(thanks to pseudonym117 for helping me shorten this significantly)

def g(s):
 for c in s:
 yield g
  • \$\begingroup\$ d=')!@#$%^&*(' is way shorter, though it uses string literals. your original answer does too though \$\endgroup\$ Commented Aug 1, 2014 at 17:58
  • \$\begingroup\$ Whoops, definitely grazed right over that limitation. I'll leave this one up anyway, and take your suggestion which for some reason I totally didn't think of. \$\endgroup\$
    – RageCage
    Commented Aug 1, 2014 at 17:59
  • \$\begingroup\$ also w=int(c) seems to not do anything at all, and g+=d[c] would need to be changed to g+=d[int(c)] \$\endgroup\$ Commented Aug 1, 2014 at 18:00
  • \$\begingroup\$ w=int(c) is to catch anything that isn't a number that may be in the string. int() raises an exception if it isn't passed a proper integer. \$\endgroup\$
    – RageCage
    Commented Aug 1, 2014 at 18:01
  • \$\begingroup\$ ah. still, combining the 2 lines into 1 would work identically. \$\endgroup\$ Commented Aug 1, 2014 at 18:03

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.