# Find one-handed words

'exaggerated' is an example of a word which can be typed on the left hand, on a normal qwerty keyboard map. 'monopoly' is an example for the right hand.

Searching the unix words file for words that can be typed on one hand. Output should be two lines: space separated list of such words for the left hand, followed by the list for the right hand. e.g.

a abaft abase abased abases abate abated abates abbess abbesses ...
h hi hill hilly him hip hippo hippy ho hokum ...


The left-hand letters are:

qwertasdfgzxcvb


The right-hand letters are:

yuiophjklnm'


Uppercase letters count as one-handed; letters with diacritics count as two-handed and hence words containing them can be ignored.

• Do capital letters require two hands or one? I suppose that characters such as "é" cannot be typed with either hand, right? Finally, I assume apostrophe is a valid right hand key, correct? – Steven Rumbalski Feb 28 '12 at 5:28
• This question isn't self-contained without a definition of left-hand and right-hand letters. – Peter Taylor Feb 28 '12 at 8:48
• One thing that might help people using regular expressions: using [a-gq-tv-xz] for the left-hand letters and ['h-puy] for the right-hand letters is slightly shorter than writing them all out. – Paul Prestidge Feb 29 '12 at 4:30

## sed, 78 bytes

1{x;s/^/! /;x};/^['h-puy]*$/IH;/^[a-gq-tv-xz]*$/I{G;x};${x;y/\n/ /;s/! */\n/p}  requires GNU sed, run with sed -n -f words.sed < /usr/share/dict/words ### Bash (100 89 chars) for x in a-gq-tvwxz h-puy\' do grep -iE ^[$x]*$/usr/share/dict/words|tr ' ' \ echo done  Note that 21 chars go to the full path to the words file: if we're allowed to assume that pwd is /usr/share/dict then 16 of those can be saved. Credit to chron for the shorter regexes. • "^([$x])*$" should be the regex – Rob Feb 28 '12 at 19:12 ## Bash, 86 for x in a-gq-tvwxz h-pyu\' do egrep ^[$x]*$/usr/share/dict/words|tr ' ' \ echo done  Taylors for, my egrep, chrons grouping of chars. By definition, if you type by two hands blind, if you like to produce an uppercase letter, you always use the left hand to produce an uppercase character of the right hand and vice versa. Of course you may produce an uppercase W with only the left hand, but you can produce junk with the left hand, too, if you like. • Beat me to the grouping on the letters, good job! – Rob Mar 2 '12 at 16:47 • It's been a race condition between Peter Taylor and me. His 100 (101?) char solution was public, when I started my post and optimization, but he finished his improvement before me, which I observed after finishing my own. I wouldn't have made the post in the same language, just with egrep and without -i, but would have made an comment instead, if he had been some minutes faster. – user unknown Mar 2 '12 at 16:54 • I thought about it right after I had made the comment correcting the regex, and left work before I had a chance to do it. Completely forgot about it by the time I got home. – Rob Mar 2 '12 at 17:04 • Your final paragraph is the reason Steven Rumbalski and I pushed for clarification, and the clarification that uppercase counts as one-handed was received more than 24 hours before you published this, so it's not really to spec. – Peter Taylor Mar 5 '12 at 11:50 ## Bourne shell, 55 chars (Or any Bourne-like shell but bash, zsh or yash) w=$1;f()echo grep -ixe[$1]*<$w;f a-gq-tvwxz;f h-puy\'


Called as sh -f words.sh /usr/share/dict/words. (of course, on systems where sh is actually bash like on some Linux distributions, use another Bourne-like shell like ash, ksh, mksh, pdksh, posh...)

## Javascript (node), 201 byte

f=require('fs');c=d='';r=(a=f.readFileSync('/dev/stdin')+c).split('\n');a.
replace(/[aqzxswcdevfrbgt]/ig,'').split('\n').map(function(k,i){k==r[i]&&(
d+=k+' ');!k.length&&(c+=r[i]+' ')});console.log(c,d)


This can probably be rewritten to a much shorter version in another language, but I just wanted to give node a try.

Run with node words.js < /usr/share/dict/words

# Q (121 140 Bytes)

Output isn't the exact same (backticks instead of spaces) but this is symptomatic of how Q displays string types.

i:read0:/usr/share/dict/words;
0N!/:i:$/:i where each (min each) each flip i in/:\:(x,upper x:"qwertasdfgzxcvb";y,upper y:"yuiophjklnm");  EDIT: Had to handle mixed case, +20 chars • You can golf this considerably for 111. $'i(&:')(min'')(+)(i:read0:/usr/share/dict/words)in/:\:(x,upper x:"qwertasdfgzxcvb";y,upper y:"yuiophjklnm'") – tmartin Mar 30 '12 at 11:26

## Ruby, 112 92 characters

EDIT: This is shorter, though not nearly as fun:

puts %w(a-gq-tv-xz 'h-puy).map{|r|File.read('/usr/share/dict/words').scan(/^[#{r}]+$/i)*' '}  Original: puts File.read('/usr/share/dict/words').scan(/(^[a-gq-tv-xz]+$)|(^['h-puy]+$)/i).transpose.map{|w|w.compact*' '}  Pretty simple regex-based solution. As with the others, you could save some characters if you're allowed to pass the filename in ARGV or if it's assumed to be in your current directory. ## Python, 130 Bytes a="\n" b="" try: while 1:v=raw_input();m=[x.lower()in"yuiophjklnm'"for x in v];v+=" ";a+=v*all(m);b+=0**any(m)*v except:print b+a  Run with python one_handed_words.py < /usr/share/dict/words • Am I allowed to take one of the solutions posted here, shorten it, and put it in my post? – snupuns Mar 2 '12 at 0:44 • If it's just small improvements, it's more friendly to post comments. If you are making a significant change, it's better to post a new answer, but nice to give credit to the answer(s) you are basing it on. – gnibbler Jun 13 '13 at 23:46 ## Haskell (191) import Char g x=all(elemx) f m[]=m f[x,y](w:ws)|g"quertasdfgzxcvb"w=f[w:x,y]ws|g"yuiophjklnm'"w=f[x,w:y]ws|1<2=f[x,y]ws main=getContents>>=mapM(putStrLn.unwords).f[[],[]].lines.map toLower  ## Python 2.7 (139 characters) import os a=set("yuiophjklnm'") c=os.read(0,9**9).lower().split() print'\n'.join([' '.join(filter(x,c))for x in a.isdisjoint,a.issuperset])  ## Perl, 72 bytes $a{/^['h-puy]+$/i-/^[a-gq-tv-xz]+$/i}.=y/\n/ /rfor<>;print@a{1,-1,$,=$/}


run with perl words.pl /usr/share/dict/words

• I get syntax error: Bareword found where operator expected at words.pl line 1, near "tr/\n/ /rfor" – wim Mar 4 '12 at 23:17
• This works for me on perl 5.14.2, and requires perl 5.14 and up (which is where the non-destructive substitution flag r was added) – Hasturkun Mar 5 '12 at 10:18

# Python - 152 137 chars (untested)

r,a,b=set("YUIOPHJKLNM'"),[],[]
try:
while 1:
w=raw_input()
s=set(w.upper())
if r|s==r:a+=w
if s-r==s:b+=w
except:for x in a,b:print' '.join(x)


edit: handle upper case and apostrophe.

## Python, 243 chars

edit: here's a more compliant program according to the question:

import sys
def o(w):
r="yuiophjklnm'";f=2;w=w.lower()
for l in w:
if(f==1)&(l in r)|(f==0)&(l not in r):return 2
f=l not in r
return f
y=[[],[],[]]
for w in sys.stdin.read().split('\n'):y[o(w)].append(w)
for i in y[0:2]:print' '.join(i)


invoke: python onehanded.py > /usr/share/dict/words or any other words file with newline-separated words

old: 141 chars, just a single-word function

returns right or left if w is onehanded, and both if both hands are used.

def o(w):
r="yuiophjklnm'";f=2
for l in w:
if(f==1)&(l in r)|(f==0)&(l not in r):f=2;break
f=[1,0][l in r]
return'rlbieogfththt'[f::3]

• Would you kindly turn that into a working program or remove the character count? Otherwise, the title is misleading. – Steven Rumbalski Feb 29 '12 at 0:16

# Q, 95 (111 with hardcoded dict path)

{$'e[(w(&)l(w)in .Q.a except a)],(e:enlist)w(&)(l:all')(w:(_)read0 -1!$x)in a:"yuiophjklnm'"}


usage

q){$'e[(w(&)l(w)in .Q.a except a)],(e:enlist)w(&)(l:all')(w:(_)read0 -1!$x)in a:"yuiophjklnm'"} "/usr/share/dict/words"
aaaaaaaaaaaaaaaaaaaaaaaaasaabergaaeaaeeaafaagaaraaraaarcaas..
hhhhhihihihihhikohikulihilihillhillhillohillyhillyhilohilum..


14 more chars if you hardcode it

$'e[(w(&)l(w)in .Q.a except a)],(e:enlist)w(&)(l:all')(w:(_)read0:/usr/share/dict/words)in a:"yuiophjklnm'"  # J, 109 1!:2&2;:^:_1('qwertasdfgzxcvb';'yuiophjkl''nm')((#@[>[:>./i.)&>/#]);:1!:1<'/usr/share/dict/words'[9!:37]0,3$_


I'm sure this can be done better, I don't know how to do string manipulation :-(

Python: 122

import os
S=set("yuiophjklnm'")
c=os.read(0,9**9).lower().split()
print"\n".join(w for w in c if set(w)<=S or set(w)^S>=S)


Launched with:

python name_of_program.py < /usr/share/dict/words


The idea is mostly the same of Dillon Cower's, but I use set(w)<=S to indicate a subset while set(w)^S>=S for a disjoint set.