| Bytes | Lang | Time | Link |
|---|---|---|---|
| 128 | Nix | 250820T112814Z | sterni |
| 011 | Thunno 2 | 230809T155549Z | The Thon |
| 030 | Bash | 140219T000815Z | user1220 |
| 048 | Scala | 220526T213954Z | cubic le |
| 080 | Haskell | 220602T060924Z | Angs |
| 027 | Retina | 220601T191234Z | math jun |
| 326 | brainfuck | 220601T184302Z | nununois |
| 050 | C++ clang | 220527T051205Z | c-- |
| 196 | Rust | 220527T094706Z | Sapherey |
| 130 | Python 3 | 220527T094229Z | Sapherey |
| 014 | Vyxal | 220526T233632Z | naffetS |
| 011 | 05AB1E | 190918T140957Z | Grimmy |
| nan | 140315T154035Z | Adam Spe | |
| 065 | Python 2.7 | 140224T171249Z | zheshish |
| 062 | C | 140219T021602Z | mattnewp |
| 110 | R | 140222T114435Z | Sven Hoh |
| 155 | QBasic | 140222T051431Z | DLosc |
| 054 | Perl | 140222T044923Z | DLosc |
| 216 | TSQL | 140222T012214Z | Jonathan |
| 101 | ECMASCRIPT | 140221T015851Z | Michael |
| 140 | C# | 140219T120527Z | RobIII |
| 080 | Python 2.7 | 140220T180335Z | jsedano |
| nan | 140220T224559Z | yegle | |
| 141 | PHP | 140219T035332Z | Rob Hoar |
| 085 | JavaScript | 140220T161454Z | George R |
| 093 | Haskell | 140220T133857Z | bazzargh |
| 032 | k [32 Chars] | 140220T044835Z | nyi |
| 024 | GolfScript | 140220T021745Z | Ilmari K |
| 121 | Python 3 | 140219T194525Z | gcq |
| 103 | EcmaScript 6 | 140219T191505Z | Toothbru |
| 092 | Frink | 140219T185127Z | maybeso |
| nan | R | 140219T165635Z | Carl Wit |
| nan | Python | 140219T154309Z | TheDocto |
| 071 | XQuery | 140219T135707Z | dirkk |
| 050 | Perl | 140219T030450Z | Rob Hoar |
| 090 | Mathematica | 140219T010136Z | DavidC |
| 070 | Smalltalk | 140219T005736Z | blabla99 |
| 038 | q [38 Chars] | 140219T025315Z | nyi |
| 087 | PHP | 140219T024004Z | SameOldN |
| 222 | C++ | 140219T022838Z | user1076 |
| 075 | Ruby | 140219T005818Z | Doorknob |
| 103 | Javascript | 140219T003726Z | Victor S |
Nix, 128 bytes
let f=s: __filter(x: x!=[]&&x!="")(__split""s);in __replaceStrings(f"abcdefghijklmnopqrstuvwxyz")(f"22233344455566677778889999")
Try it here, though this version is longer since the Tvix implementation (which supports wasm) of the Nix language doesn't support the __ prefixed aliases for builtin functions.
The expression returns a function which accepts a string and returns the appropriate phone number:
import ./golf.nix "1-800-golfed"
# => "1-800-465333"
I'm mostly posting this because I expected the best solution to be much longer. Nix has no character arithmetic nor a built in way to work with strings character by character. Luckily the output is supposed to be a string, so we can use replaceStrings and just have to create the lists of strings it expects. I decided to write a shorter version of stringToCharacters by splitting using an empty regex (which still requires some postprocessing). Importing the Nixpkgs library wouldn't have helped, as with import<nixpkgs/lib>; is already pretty long.
Thunno 2, 11 bytes
Ạż6+kP÷T9vṆ
Explanation
Ạż6+kP÷T9vṆ # Implicit input
Ạ # Push the lowercase alphabet
ż # Without popping, push [1..26]
6+ # Add 6 to make it [7..26]
kP÷ # Floor divide each by pi
T9v # Replace the 10 with a 9
Ṇ # Transliterate the input
# Implicit output
Bash, 30
Edit: Thank you Doorknob for eliminating 3 chars
tr a-z 22233344455566677778889
Example:
Scala, 49 48 bytes
_.map(c=>if(c>96)(c/3.2+20).toChar min'9'else c)
Maps abcdefghijklmnopqrstuvwxyz to 22233344455566677778889999 via (c/3.2+20).toChar min'9'
(saved 1 byte thanks to Kevin Cruijssen)
Haskell, 80 bytes
d c|elem c['a'..'z']="22233344455566677778889999"!!(fromEnum c-97)|1>0=c
l=map d
Retina, 27 bytes
T`l`22233344455566677778889
Port of the Bash solution. Transliterates each lowercase letter to a digit between 2 and 9. The list is implicitly padded with 3 additional 9s
brainfuck, 326 bytes
,[>+[-[---<]>>-]<--<<<[>>>>+<[->[-]>+<<]>[-<<+>>]>[-<<+>>]<<-<<+<-]+>>[<<->[-]>->[<+>+]<->>+++++[>+++++<-]>[<+>-]+<<<[>>-<+<-]>[<+>-]>[>-<[-]]>[<<<->>>-]++++[>++++<-]>+<<<<[>>+>>[-<<[-]>+>]<<[-<+>]>[->+<]>-<<<<<+>-]>>>>[-]<<<[<<->>-]<+++<[->-[>+>>]>[+[-<+>]>+>>]<<<<<]>[-]>[-]+++++[>++++++++++<-]>.[-]<<]<<[->.>>[-]<<<]>[-]<,]
For each character:
- Check if it's a letter. If not, print it and go to the next character.
- Check if it's 'z'. If it is, subtract 1 to make it 'y'
- Check if it's after 'r'. If it is, subtract 1 to realign it with the number grid.
- Divide the letter number by 3.
- Add the result to 50 ('2') and print it.
stage0 memory layout:
| input x | input backup | compare result z | compare val y | compare t0 | compare t1 |
stage1:
| else flag | input backup | prev compare result / letter index y | inv letter index / compare t0 | compare t1 | compare val x |
stage2:
| else flag | letter index backup | letter index x | compare result z | compare t0 | compare t1 | compare val y |
,[ Read first character
>+[-[---<]>>-]<-- Check if input is greater than 96 (a lowercase letter)
<<<[>>>>+
<[->[-]>+<<]
>[-<<+>>]
>[-<<+>>]
<<-<<+<-
]
+ Set else flag
>>[ If input is a letter:
((stage1))
<<->[-]>- Clear the result/else flags
>[<+>+]<- Invert the letter index
>>+++++[>+++++<-]> Check if letter 25 (z)
[<+>-]+
<<<[>>-<+<-]
>[<+>-]
>[>-<[-]]
>[<<<->>>-] If it is subtract 1 to change it to y
((stage2))
++++[>++++<-]>+ Check if greater than letter 17 (r)
<<<<[>>+
>>[-<<[-]>+>]
<<[-<+>]
>[->+<]
>-<<<<<+>-
]
>>>>[-] Clear y
<<<[<<->>-] If it is subtract 1 to normalize indices
<+++<[->-[>+>>]>[+[-<+>]>+>>]<<<<<] Divide normalized index by 3
>[-]>[-] Clear tempvars from division
+++++[>++++++++++<-]>. Add 50 ('2') to result and print it
[-]<< Clear letter index
((stage0))
]<<[ If input isn't a letter:
- Clear the result flag
>. Just print the character
>>[-]<<< Clear the letter index
]
>[-]<, Next input
]
C++ (clang), 50 bytes
[](auto&s){for(auto&c:s)c=c>96?20-c/122+5*c/16:c;}
this is a port of mattnewport's C solution.
Rust, 196 bytes
x.iter().map(|x|match x{'a'|'b'|'c'=>'2','d'|'e'|'f'=>'3','g'|'h'|'i'=>'4','j'|'k'|'l'=>'5','m'|'n'|'o'=>'6','p'|'q'|'r'|'s'=>'7','t'|'u'|'v'=>'8','w'|'x'|'y'|'z'=>'9',_=>*x}).collect::<Vec<_>>();
Power of match. Yet match for every letter feels unnecessarily tedious. Still trying to grasp iter() and subsequent functions
Python 3, 130 bytes
d=lambda x:str(int((ord(x)-96)*.31769+1.76715))
def f(s,c=''):
for i in s:c+=(d(i)if i!='z'else'9')if i.isalpha()else i
print(c)
Uses the formula y = (x * .31769) + 1.76715 to approximate the given relation. Sadly this formula gives wring value for z hence requires one additional check
Vyxal, 14 bytes
ka:ż6+kiḭṪ9JṅĿ
ka:ż6+kiḭṪ9JṅĿ
ka: # Push the alphabet twice
ż # Length range: [1..26]
6+ # Add 6: [7..32]
kiḭ # Floor divide by pi: [2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,10]
Ṫ9J # Remove the last item and append 10
ṅ # Join by nothing to make a string
Ŀ # Transliterate the input from the alphabet to this
05AB1E, 11 bytes
Aā6+žq÷T9:‡
A # alphabet: "abcdefghijklmnoqrstuvwxyz"
ā # length range: [1..26]
6+ # add 6 to each: [7..32]
žq÷ # divide by pi: [2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,10]
T9: # replace 10 with 9
‡ # transliterate the input (a => 2, ..., z => 9)
VB.net (61c)
Excludes the 45c min for a valid vb.net program.
Module P
Sub Main(A()As string)
For Each x In A(0).ToUpper
Console.Write(If(x<"A"or x>"Z",x,Chr(Asc(x)\4+35)))
Next
End Sub
End Module
Python 2.7, 66 65
Anakata's Original
for c in raw_input():print'\b'+(`(ord(c)-97)/3+2-(c in('svyz'))`if c>'`'else c),
Further golfed
for c in input():print(ord(c)-91)/3-(c in('svyz'))if c>'`'else c,
I don't have enough reputation to comment on @anakata's answer, so I made a separate post here. I had the same idea (taking the ordinance modulus 3) but couldn't figure out how to print the right numbers for s - z.
Anyways, the golf improvements I made:
changed
raw_inputtoinputremoved the extraneous
'\b'and parentheses and single quotesremoved the
+2offset and placed that in the original subtraction (97 - (3 * 2) = 91)
Tested with the Python 2.7.6 interpreter. Assumes, per the rules, a string input.
C, 83 78 77 65 63 62
main(c){for(;~(c=getchar());putchar(c>96?20-c/122+5*c/16:c));}
R, 110
s=strsplit(scan(,""),"")[[1]];i=grep("[a-z]",s);s[i]=sort(c(1:24%%8+2,7,9))[match(s[i],letters)];cat(s,sep="")
Example:
> s=strsplit(scan(,""),"")[[1]];i=grep("[a-z]",s);s[i]=sort(c(1:24%%8+2,7,9))[match(s[i],letters)];cat(s,sep="")
1: 1-800-program
2:
Read 1 item
1-800-7764726
QBasic, 155
Ah, the memories...
INPUT n$
FOR i=1 TO LEN(n$)
c$=MID$(n$,i,1)
a=ASC(c$)
IF 97>a THEN
PRINT c$;
ELSE IF 122>a THEN
PRINT STR$(a\3.2-28);
ELSE
PRINT 9;
END IF
NEXT i
This should have been shorter, but I was testing with repl.it, which doesn't allow single-line IF statements and behaves strangely if you leave the variable off of NEXT i. It also doesn't recognize the ASC function, so to run the code you'll need to add this workaround at the beginning:
DECLARE FUNCTION ASC(s$)
FUNCTION ASC(s$)
FOR j=1 TO 255
IF CHR$(j)=LEFT$(s$,1) THEN
ASC=j
END IF
NEXT j
END FUNCTION
(The second time you run it, the interpreter will complain unless you remove the DECLARE FUNCTION line, go figure.)
Perl, 54
print map{/[a-y]/?int(5/16*ord)-28:/z/?9:$_}<>=~/./gs
Shoot, @RobHoare still beat me by 4 characters. :)
T-SQL, 216 bytes
I spent quite some time over the past couple of nights painstakingly creating a mathematical sequence function that would round correctly to generate the proper ASCII codes for the numbers from the alphabetical ASCII codes. It had a ridiculous number of decimal places in the coefficients, but it worked.
However, mattnewport's rational approach works in SQL as well, at a much lower cost of bytes, so I am shamelessly scrapping my own math in favor of his. Go up-vote him, it's an elegant solution!
Here's mine:
DECLARE @p VARCHAR(MAX)='';WITH t AS(SELECT ASCII(LEFT(@s,1))c,2 i UNION ALL SELECT ASCII(SUBSTRING(@s,i,1)),i+1FROM t WHERE i<=LEN(@s))SELECT @p=@p+CHAR(CASE WHEN c>96THEN 20-c/122+5*c/16 ELSE c END)FROM t;SELECT @p
This uses a recursive CTE to make an impromptu stack of the characters in the phone number and translate the letters on the fly, then a bit of SQL trickery (SELECT @p=@p+columnValue) to recompose the string from the CTE without requiring another recursion construct.
Output:
DECLARE @s VARCHAR(MAX)='1-800-abcdefghijklmnopqrstuvwxyz'
--above code runs here
1-800-22233344455566677778889999
ECMASCRIPT, 101 (with input)
"1-800-PROGRAM".replace(/./g,function(c){
return "22233344455566677778889999"[c.charCodeAt(0)-65]||c})
Newline added for clarity. 85 characters if the input is in a variable.
C# 140
using System.Linq;class P{static void Main(string[]a){System.Console.Write(string.Concat(a[0].Select(d=>(char)(d>96?20-d/122+5*d/16:d))));}}
Python 2.7, 80
for c in raw_input():print'\b'+(`(ord(c)-97)/3+2-(c in('svyz'))`if c>'`'else c),
I am new to python, so I'm sure there must be a way to golf this even further, it's a different aproach, hope you guys like it, my god, is python pretty!
Run example:
- input: 01-800-abcdefghijklmnopqrstuvwxyz
- output: 01-800-22233344455566677778889999
Python
import string
trans = str.maketrans(string.ascii_lowercase,
'22233344455566677778889999')
print("1-800-ask-usps".translate(trans))
PHP, 141
Not the shortest, but more fun:
<?php foreach(str_split($argv[1])as$c){$v=ord($c);if($v>114){$v--;}if($v==121){$v--;}if($v<123&$v>96){echo chr(ceil($v/3+17));}else{echo$c;}}
More readable:
<?php
foreach (str_split($argv[1]) as $c) {
$v=ord($c);
if ($v>114) {$v--;}
if ($v==121){$v--;}
if ($v<123 & $v>96){
echo chr(ceil($v/3+17));
} else {echo $c;}
}
JavaScript, 85
JavaScript is never going to win the golf wars, but I like it and I wanted to do something different than jump on the @ace bandwagon.
alert(prompt().replace(/[a-z]/g,function(a){for(i=7;a<"dgjmptw{"[i--];);return i+4}))
Haskell, 93C
t[]_ a=a
t(b:c)(d:e)a
|a==b=d
|True=t c e a
y=map(t['a'..'z']"22233344455566677778889999")
Usage
y "1-800-program"
k [32 Chars]
{(.Q.a!|,/(4 3 4,5#3)#'|$2+!8)x}
Usage
{(.Q.a!|,/(4 3 4,5#3)#'|$2+!8)x}"stack exchange"
"78225 39242643"
GolfScript, 24 chars
{.96>{,91,'qx'+-,3/`}*}%
Test input:
0123456789-abcdefghijklmnopqrstuvwxyz
Test output:
0123456789-22233344455566677778889999
Explanation:
{ }%applies the code between the braces to each character of the input..96>{ }*executes the code between the inner braces if and only if the ASCII code of the character is greater than 96 (i.e. it is a lowercase letter).The first
,turns the character into a list of all characters with lower ASCII codes, and91,'qx'+-filters out all characters with ASCII codes less than 91, as well as the lettersqandx, from the list. Thus, for example, the characteragets turned into the 6-character list[\]^_`, whilezgets turned into the 29-character list[\]^_`abcdefghijklmnoprstuvwy.The second
,counts the elements remaining in the list, and3/divides this count by three (rounding down). Finally, the`turns the resulting number (in the range 2 – 9) into a string.
Thus, as per spec, hyphens and numbers are left unchanged, while lowercase letters are mapped into numbers according to the reference keypad diagram. The code will actually cleanly pass through all printable ASCII characters except for lowercase letters (which as mapped as described) and the characters {, | and } (which are mapped to the two-character string 10). Non-ASCII 8-bit input will produce all sorts of weird numeric output.
After all this, it's a bit disappointing that this only beats the trivial bash solution by just six chars.
Python 3, 121
print("".join((lambda x:"22233344455566677778889999"[ord(x)-97] if ord(x)>96 and ord(x)<123 else x)(i) for i in input()))
EcmaScript 6 (103 bytes):
i.replace(/[a-z]/g,x=>keys(a='00abc0def0ghi0jkl0mno0pqrs0tuv0wxyz'.split(0)).find(X=>a[X].contains(x)))
Expects i to contain the string.
Try it in any recent version of Firefox. I've not tried Google Chrome.
Frink, 92
A rather verbose language, I know. This checks 8 values instead of 26 without having to type out the compares. Can any of the above "222333444.." solutions be reduced in a similar way?
Using built in structures, 107
co=new OrderedList
co.insertAll[charList["cfilosv{"]]
println[input[""]=~%s/([a-z])/co.binarySearch[$1]+2/eg]
Using a custom recursive function, 92
fn[x,a]:=x<=(charList["cfilosv{"])@a?a+2:fn[x,a+1]
println[input[""]=~%s/([a-z])/fn[$1,0]/eg]
R, very long but fun
foo <- '1-800-splurghazquieaobuer57'
oof <- unlist(strsplit(foo,''))
#don't count that part - it's input formatting :-)
digout <- unlist(strsplit('22233344455566677778889999',''))
oof[oof%in%letters[1:26]] <- unlist(sapply(oof[oof%in%letters[1:26]], function(j) digout[which(letters[1:26]==j)] ))
Python, very ungolfed
Since everyone is copying ace, i decided to post the code i made up before i submitted the question:
def phonekeypad(text):
c = ['','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
st = ""
for i in list(text):
a = False
for t in range(len(c)):
if i in c[t]:
st += str(t)
a=True
if a == False:
st += str(i)
return st
XQuery, 71
BaseX was used as XQuery processor. $i is input.
translate($i,"abcdefghijklmnopqrstuvwxyz","22233344455566677778889999")
Not the shortest answer, but quite short and very readable.
Perl, 50
Another obvious copy of Ace's bash answer
($_)=@ARGV;y/a-z/22233344455566677778889999/;print
Mathematica 90
This follows the logic of @ace's solution:
StringReplace[#,Thread[CharacterRange["A","Z"]->Characters@"22233344455566677778889999"]]&
Example
StringReplace[#1,Thread[CharacterRange["A","Z"]->
Characters@"22233344455566677778889999"]]&["VI37889"]
8437889
Smalltalk, 79 70
input is s:
s collect:[:c|' 22233344455566677778889999'at:1put:c;at:(($ato:$z)indexOf:c)+1]
probably not a candidate for being shortest - but may be of interest for an old trick to avoid a test for a not-found condition (indexOf: returns 0 in this case). So no special test for letters is needed. Some Smalltalks however, have immutable strings, and we need 4 more chars ("copy").
Oh, a better version, which even deals with immutable strings in 70 chars:
s collect:[:c|c,'22233344455566677778889999'at:(($ato:$z)indexOf:c)+1]
q [38 Chars]
{(.Q.a!"22233344455566677778889999")x}
Inspired by @ace's solution
Example
{(.Q.a!"22233344455566677778889999")x}"stack exchange"
"78225 39242643"
PHP, 87
echo str_ireplace(range('a','z'),str_split('22233344455566677778889999'),fgets(STDIN));
C++ - 222 chars
Longest solution so far:
#include<iostream>
#include<string>
#define o std::cout<<
int main(){std::string s;std::cin>>s;for(int i=0;i<s.size();i++){int j=s[i]-97;if(j<0)o s[i];if(0<=j&j<15)o 2+j/3;if(14<j&j<19)o 7;if(18<j&j<22)o 8;if(21<j&j<26)o 9;}}
Ruby, 75 chars
gets.chars{|c|$><<"22233344455566677778889999#{c}"[[*?a..?z].index(c)||-1]}
Uses the deprecated chars with block, and prints each letter individually with $><<. I also like [[*?a..?z].index(c)||-1]; it grabs the character corresponding to that letter of the alphabet if it's a letter, and the last character (which happens to be the test character unchanged) if not.
Ruby, 43 (or 35) chars
Blatantly stealing from @ace ;)
puts gets.tr'a-z','22233344455566677778889'
Shave off 8 chars if I can run in IRB with the variable s as the string:
s.tr'a-z','22233344455566677778889'
Javascript - 103 characters
alert(prompt().replace(/[a-z]/g,function(y){y=y.charCodeAt(0)-91;return y>27?9:y>24?8:y>20?7:~~(y/3)}))