# Which Row is the Key On?

Given any of the following characters (or a newline):

1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?  Your program must output the row that it is on the keyboard Because my keyboard is (almost) out of battery, your code must be as short as possible The keyboard your program should use (for the row lookup), should look like: Row 1:~ !1@2 #3$4 %5^6 &7*8 (9)0 _-+=

Row 2:                         Q W E R T Y U I O P {[ }]    |\
Row 3:                              A S D F G H J K L :; "' return
Row 4:                                 Z X C V B N M <, >. ?/
Row 5:                                                    space

Where   return is a newline. Empty keys don't mean anything.

"$" 1 "R" 2 "a" 3 "?" 4 "\n" 3 " " 5  where \n is a newline character. ## Specifications • Your program should be case insensitive • Your program only needs to handle the characters on the keyboard shown • Perhaps classification? Jan 7, 2016 at 1:42 • Is that a double-nested kbd? Jan 7, 2016 at 4:04 • I remember years ago using some language that returned keypresses as as 100×row+position... Would have been perfect for this, but unfortunately I don't remember what it was. Maybe some form of BASIC... – Adám Jan 7, 2016 at 13:35 • @NBZ Is it Blitz Basic? Jan 7, 2016 at 18:43 • @wizzwizz4 Have you tried BlitzPlus? it's free and looks like it's what you want. Jan 25, 2016 at 22:42 ## 21 Answers # JavaScript (ES6), 105102 101 bytes c=>/[~0-9!@#-&^(-+_=-]/.test(c)+/[asdfghjkl;:'"\n]/i.test(c)*3+/[zxcvbnm,<.>/?]/i.test(c)*4||++c*7^2  ## Explanation In JavaScript test returns a boolean which acts the same as 1 or 0 so I multiply them by their row. Testing for row 2 took the most bytes so I used that one as the default if no others matched. c=> /[~0-9!@#-&^(-+_=-]/.test(c) // row 1 regex +/[asdfghjkl;:'"\n]/i.test(c)*3 // row 3 regex +/[zxcvbnm,<.>/?]/i.test(c)*4 // row 4 regex ||++c // space ++ = 1, any character on row 2 ++ = NaN *7^2 // 7 XOR 2 = 5, NaN XOR 2 = 2  ## Test var solution = c=>/[~0-9!@#-&^(-+_=-]/.test(c)+/[asdfghjkl;:'"\n]/i.test(c)*3+/[zxcvbnm,<.>/?]/i.test(c)*4||++c*7^2 <textarea id="input">-</textarea><br /> <button onclick="result.textContent=solution(input.value)">Go</button> <pre id="result"></pre> • > NaN XOR 2 = 2 — ??? Jan 7, 2016 at 3:05 • @ThomasKwa That's just how JS works lol. If c="q", ++c = NaN, NaN*7 = NaN, NaN^2 converts the operands to integers (uncastables like NaN become 0) then does 0 XOR 2 which is 2. Jan 7, 2016 at 3:10 # Pyth, 6266 65 bytes ?zh@+,4Zmid2c.Bi."0fÀÓ¸[9Ñ¶¤KïLäHÉðbÀ]ü©¬vS"16 2-CzCd3  Try it online. Uses a packed string representing a number in hex which, when chopped into two-bit chunks, represents the row of every character except and ! as a value from 0 to 3. We leave out and ! so we don't have to store 4 or have a 0 at the start of this number, then add their row values using +,4Z. Once we've turned the string into row values, all we have to do is use the character code of the input to index into the array of values, and then add 1. Newline is handled separately because it's interpreted by Pyth as an empty string and so has a character code of 0. This would be shorter if I could figure out how to use base 256 in Pyth, but I can't quite make it work. • o.0 starts squeezing Japt Jan 7, 2016 at 21:25 • this puts me to shame Jan 7, 2016 at 23:14 • :( I forgot about newline! @nicael you're back to being on top. – Luke Jan 7, 2016 at 23:45 • Now we're dead even! – Luke Jan 7, 2016 at 23:49 • You need to escape null bytes in Pyth. Jan 7, 2016 at 23:49 ## Glava 1.5, 164 bytes Glava is a dialect of Java that makes Java code shorter. This code is unfortunately non-competitive as the commit (2 hours late...) used was made after this challenge, which fixed some vital bugs that would not allow this program to work. p(A[0].matches("[0-9-=~!@#$%^&*()_+]")?1:A[0].replace("\\n","\n").matches("(?i)[asdfghjkl;':\"\n]")?3:A[0].matches("(?i)[zxcvbnm,.\\/<>?]")?4:A[0].matches(" ")?5:2


This is a full program that takes input via command-line arguments. Works by simply testing for which row regex it matches, then outputs the corresponding number.

• Glava = Guava + Java? Jan 7, 2016 at 3:32
• @Doᴡɴɢᴏᴀᴛ Glava = Golf + Java ( it was Conor's idea) Jan 7, 2016 at 3:38
• Indeed! @Doᴡɴɢᴏᴀᴛ Jan 7, 2016 at 4:04

print(int(("~!1@2#3$4%5^6&7*8(9)0_-+=""qwertyuiop{[}\|"+"]"*11+'asdfghjkl;:"\n'"'"*13+"zxcvbnm,<.>/""?"*14+" ").index(input().lower())/26)+1)  There is probably a shorter way that I am overlooking ¯\_(ツ)_/¯ # Pyth, 98 |+++l:"~0123456789!@#$%^&*()_-=+"z1*l:"asdfghjkl;:'\"\n"rz0 1 3*l:"zxcvbnm,<.>/? "rz0 1 4 l:dz1 2


not sure how to get the 0-9 range working for some reason :|, inspired by user81655's answer

• You can use jkUT for the string with the range 0 to 9, not sure if there's a shorter way. You can also used packed strings to save a few bytes, e.g. ."!~WÏù¹_(<]úÝ" for "~!@#$%^&*()_-=+". – Luke Jan 7, 2016 at 3:36 • From @benstopics, this does fail for regex metacharacters Jan 7, 2016 at 14:53 # Bash, 108 No Bash answer? Bash answer. grep -Fin is definitely the right tool for this job. This program is in two files. ## k, 73 bytes 1234567890-=~!@#$%^&*()_+
qwertyuiop[]\{}|
asdfghjkl;':"
zxcvbnm,./<>?


There are 5 lines, the last one is a space. If you have trouble reproducing the file, the base64 is:

YDEyMzQ1Njc4OTAtPX4hQCMkJV4mKigpXysKcXdlcnR5dWlvcFtdXHt9fAphc2RmZ2hqa2w7JzoiCnp4Y3Zibm0sLi88Pj8KIA==


## b, 34 bytes

This is the program itself, it takes input as the only command line argument.

grep -Fin "$1" k|tail -n3|head -c1  Score: 34 + 73 + 1 (for k's filename) = 108 bytes ## Ungolfed grep --fixed-strings --ignore-case --line-number "$1" k|tail --lines=3|head --bytes=1


## Explanation

• grep - search a file for lines matching a string or regular expression, output only those lines
• -F aka --fixed-strings - disable regular expressions so [ etc. are handled correctly
• -i aka -y aka --ignore-case - case-insensitive matching
• -n aka --line-number - show the line number and : before every line (e.g. 4:zxcvbnm,./<>?)
• "$1" - search for the script's first command-line argument, the quotes are necessary to handle newline and space • k - search in file k • This grep command will match all five lines if the input is a newline, and only one line otherwise. • | - pipe, send standard output of one command to standard input of the next • tail - output the last N lines or characters of standard input • -n3 aka --lines=3 - output the last 3 lines • If the input wasn't a newline, there is only one line to process, which starts with the row number because of the -n flag on grep. Otherwise, this command takes only lines 3, 4 and 5 (the last 3 lines). • | - pipe • head - output the first N lines or characters of standard input • -c1 aka --bytes=1 - output the first character • If the input wasn't a newline, this takes the first character, which is the line number where the input is found. If the input is a newline, it takes the first character of lines 3, 4 and 5 combined, which is 3, which happens to be the correct row number for newline. ## Japt, 7370 66 bytes 2+qØÆyuiop\{}[]|\\1dfghjkl;: '1zxcvbnm,.<>?/\"1 q1 ®bUv)<0} b!1  Try it online! (in the example, the input is literally a newline) • Nice, shortest so far! Jan 7, 2016 at 15:21 • @Eth yup, at least once I should post something short :D Jan 7, 2016 at 15:25 • A couple bytes shorter Jan 7, 2016 at 15:29 • @Eth Heh, !1 is something that matches "false", finally I know how to do it, thanks :) Jan 7, 2016 at 15:32 • @Eth halp, needs 5 bytes to beat Pyth. Jan 7, 2016 at 23:04 # Java, 300 bytes import java.util.Scanner;public class A{public static void main(String[] args){String g="~!1@2#3$4%5^6&7*8(9)0_-+=qQwWeErRtTyYuUiIoOpP[{]}\\|aAsSdDfFgGhHjJkKlL;:\'\"\r";Scanner i=new Scanner(System.in);int f=g.indexOf((i.nextLine().charAt(0)));System.out.print(f<0?4:(f<26?1:(f<53?2:(f<76?3:5))));}}


I'm not an expert, and this is my first attempt at golfing, but I figured, what the hell, why not? Above is the full program version, the actual code that goes into it would most likely take a decent amount of characters off.

• just noticed it crashes with an empty input(new line/carriage return). will fix when I can Jan 8, 2016 at 17:33
• Welcome to the community! Sep 28, 2016 at 18:25
• Welcome (bit late since you posted in January xD). You can golf it quite a bit without changing your current approach like this: class A{public static void main(String[]a){int f="~'!1@2#3$4%5^6&7*8(9)0_-+=qQwWeErRtTyYuUiIoOpP[{]}\\|aAsSdDfFgGhHjJkKlL;:\'\"\r".indexOf(new java.util.Scanner(System.in).nextLine().charAt(0));System.out.print(f<0?4:f<26?1:f<53?2:f<76?3:5);}} (243 bytes) I removed some unnecessary parenthesis; shortened args; removed public ; directly used the String and Scanner; and removed the import now that java.util.Scanner is used once. Oct 25, 2016 at 9:26 • 219 bytes you don't need to use Scanner for this Nov 26, 2017 at 17:33 ## Pyth, 105 bytes J?<l-c".^$*+?{}[]\|()"1]z14+\\zrz0?qJd5?:"qwertyuiop[]\|"J)2?:"asdfghjkl;':\"\n"J)3?:"zxcvbnm,./<>?"J)4 1


Explanation:

J?<l-c".^$*+?{}[]\|()"1]z14+\\zrz0 # Escape input if regex metachar ?qJd5 # Check space ?:"qwertyuiop[]\|"J)2 # Check second row ?:"asdfghjkl;':\"\n"J)3 # Check third row ?:"zxcvbnm,./<>?"J)4 # Check fourth row 1 # If none of these, must be on first row.  I decided to choose the first row as the "must be if nothing else" row because it required the most bytes to represent even after golfing. • Welcome to Programming Puzzles and Code Golf! Use comments to make @JuanPotato get it. However, that needs 50 rep. So you need to work. Jan 7, 2016 at 14:32 # Perl 6, 128 bytes say 1+(/<[-\d=~!@#$%^&*()_+/]>/,/<[qwertyuiop[\]\\{}|]>/,/<[asdfghjkl;':"\n]>/,/<[zxcvbnm,./<>?]>/,' ').first: @*ARGS.lc~~*,:k


I make a list of regexes containing character classes along with a string literal space. I then call the first method on the list (which is just the method version of the first higher order function), using smartmatch to compare the argument passed to the program against the current item in the list. Note that smartmatch does "the right thing" for both regexes and a string literal. The :k optional parameter to first causes the method to return the index of the matching item in the list, which I then add 1 to and output via say.

Note that when using this program you will have to properly escape certain characters like  and space in your shell. For instance: perl6 keyboard.p6 \

• Since nobody said it yet, welcome to Programming Puzzles & Code Golf! Sep 28, 2016 at 18:24

## Python 3, 89 bytes

print("qwertyuiop{}[]\\|asdfghjkl;:\"\n'''zxcvbnm,.<>/???? ".find(input().lower())//16+2)


As I can't comment yet, I'm posting the improvement for the current Python 3 answer separately.

Edit: All code in print now and further tweaked.

• This is merely a snippet and therefore not a valid answer, you need to wrap it in a print statement (making it a full program) or turn it into a function. Nov 26, 2017 at 16:42
• @FlipTack: You're right. I've incorporated your suggestion. Nov 26, 2017 at 16:51
• Welcome to PPCG! Nov 26, 2017 at 17:01
• @MartinEnder: Thank you! :-) Nov 26, 2017 at 17:30

## JavaScript ES6, 114 bytes

n=>[qwertyuiop{}[]|\\,asdfghjkl;:
',zxcvbnm,.<>?/", ].map(x=>+(x.indexOf(n.toLowerCase())<0)).indexOf(0)+2


Another JavaScript solution. The principle is to return the index of the input char in the array of rows plus 2 (so as the 0-9 row returns -1, i.e. not exists, -1+2=1. q is in the first string of the array, so it returns 0+2=2nd row).

# Perl, 9677 76 bytes

Run using perl -p. Make sure you're feeding it just single characters; for example, to run it from a file key.pl (to avoid mucking around with shell escape sequences) echo -n q|perl -p key.pl.

$_=/[\d~!@#-&(-+_=-]/+/[adfghjkls"':; ]/i*3+/[bcnmvxz<>,.?\/]/i*4+/ /*5||2  Abusing the regex range functionality is fun. • To me this doesn't work, running it I get the index of the row + 3 (i.e. 3 instead of 0, 7 instead of 4, etc.). Jan 7, 2016 at 8:20 • It's sensitive to how you provide the input. You're probably providing a character followed by a newline. I use echo to precisely control the input -- eg. echo -n q|perl -n key.pl, which correctly produces 2. – Mark Jan 7, 2016 at 8:29 • Oh, I see. Well, that also explains why you don't chomp the input. Jan 7, 2016 at 8:39 • If I chomped the input, I wouldn't be able to return '3' for the return key. – Mark Jan 7, 2016 at 8:42 • Hey @Mark, you don't need the $_=~ for the matches, m// (which is what /.../ is) works on $_ automatically! Also if you use -p instead of -n you can use $_= instead of print to save a couple more bytes. Using a literal newline instead of \n can save you another byte too! That should reduce your code quite a bit! Might be worth adding an example usage as well so anyone testing knows you need to use echo -n :) Jan 7, 2016 at 9:51

# PHP, 173 bytes

The idea here was to use the regex capturing group number as the row index. Probably some more optimizations in the regex itself.

$i=$argv[1];preg_match("%([!#-&\(-+-0-9=@^-~])|([EIO-RT-UWY[-]eio-rt-uwy{-}])|([\"':-;ADF-HJ-LSadf-hj-ls])|([,.-/<>-?B-CM-NVXZb-cm-nvxz])%",$i,$m);echo array_flip($m)[$i];


The preg_match() call will create an array $m of matches, and if we were to print that, it'd look something like this (assuming z was the input): Array ( [0] => 'z', [1] => '', [2] => '', [3] => '', [4] => 'z' )  Flipping that array, by swapping keys and values, moves left to right and only keeps the last distinct key, so we end up with: Array ( 'z' => 4, '' => 3 )  Then we use the input character as the index in the array to get our result. # C, 145 143 136 132 127 106 104 bytes #define c"\x7ea6a6f8\x5777595" f(a){return a-32?L"\x200000\0\xf3008020\xf2a00000"c c[a>>4]>>a%16*2&3:4;}  Try it online! This uses index() from POSIX.1-2001 and is deprecated in POSIX.1-2008. This assumes ASCII and 32 bit ints. # Ruby, 82 bytes ->i{1+((0>r=i.ord-33)?r%5:"bc7xdutvz4ind3bwqf6mcu5vxiahnmlfs93c".to_i(36)>>2*r&3)}  Try it online! # CJam, 125 bytes q_" "={;5}{"1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\"    zxcvbnm,./ZXCVBNM<>?    "\#26/1+}?


### Explanation

q                          e# read input
_" "=                     e# decide if the input is a space
{;5}                 e# if it is, push 5
{"..."\#26/1+}?  e# if it isn't, push the correct row


# SpecBAS - 178 bytes

1 a$="~!1@2#3$4%5^6&7*8(9)0-_+=qQwWeErRtTyYuUiIoOpP{[}]|\aaaaAsSdDfFgGhHjJkKlL:;'"#34#13"zzzzzzzZxXcCvVbBnNmM<,>.?/"+" "*26
2 INPUT k$: IF k$="" THEN k$=#13 3 ?CEIL(POS(k$,a$)/26)  I used a long string where each row is 26 characters long (#34 is code for double quote and #13 is code for return). Then print the result of rounding position/26. # C#6, 201 bytes Nothing special here. I found it cheaper to just write both cases rather than use ToUpper() due to the string's fixed width. using C=System.Console;class P{static void Main(string[]a)=>C.Write("1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'\raASDFGHJKL:\"\nazxcvbnm,./zzzZXCVBNM<>?zzz ".IndexOf(a[0])/26+1);}


Indented:

using C=System.Console;
class P{
static void Main(string[]a)=>
C.Write("1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'\raASDFGHJKL:\"\nazxcvbnm,./zzzZXCVBNM<>?zzz ".IndexOf(a[0])/26+1); }  • I can't see this working for ~ or ? Jan 7, 2016 at 9:56 • @AshBurlaczenko, thanks! I missed that key. Fixed with no change to my score. Jan 10, 2016 at 9:59 # Python 2, 146 bytes e="\n";lambda x:("1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\""+e*4+"zxcvbnm,./ZXCVBNM<>?"+e*13+" ").index(x)/26+1


# Excel, 132 bytes

=INT((FIND(A1,"1234567890-=~!@#\$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:""aaa zxcvbnm,./ZXCVBNM<>?zzzzzz ")-1)/26)+1

Attempts to use the case in-sensitive SEARCH() instead of FIND() revealed that Excel matches ~, * and ? to (tick). The matching of?means we can't useSEARCH()`, which would have shaved a massive 5 bytes...