Some versions of the standard Android calculator app allow you to press a key, like 'sin' and then the 'del' key to make it 'si'. Probably just a bug which they can't be bothered with removing.

Screenshot of Android calculator

The following letters/letter groupings are typable:



So, 'tasteless' is typable, because ta-s-t-e-l-e-s-s and so is 'clogs' because 'c-log-s'. However 'got' is not typable, neither is 'an' or 'xyz'.

Write a program that takes a single word (or sequence of letters, only a-z in input) as input and produces output to indicate if a word is typable or not.

Output may be a single character/letter/digit/etc. or it may be larger. All typable words should produce the same output. All non-typable words should also produce the same output.

P.S. Just out of curiosity, is 'tasteless' the longest dictionary word that is typable?

  • 1
    \$\begingroup\$ Just to be clear: We output a single, consistent digit or letter of our choice to indicate the word is typeable, and a different, single, consistent digit or letter of our choice to indicate the word is not typeable. Is that correct? \$\endgroup\$
    – Dennis
    Dec 4 '16 at 16:36
  • 3
    \$\begingroup\$ The longest word I could find is 10 letters, coelostats. \$\endgroup\$ Dec 4 '16 at 21:48
  • 1
    \$\begingroup\$ So, is "πe" not a word? \$\endgroup\$
    – Mr Lister
    Dec 5 '16 at 9:15
  • \$\begingroup\$ @Dennis Ya, more or less. \$\endgroup\$ Dec 5 '16 at 14:43
  • 1
    \$\begingroup\$ Another 11: sissinesses \$\endgroup\$
    – Chris H
    Dec 6 '16 at 13:29

15 Answers 15


Perl, 47 43 41 + 1 = 42 bytes

-4 bytes thanks to @Sunny Pun. -2 bytes thanks to @Brad Gilbert b2gills and @Downgoat

Run with the -n flag.


It can definitely be golfed futher, but in the spirit of competition, I'm leaving the mostly-original regex I came up with at the beginning. Returns nothing if true, 1 if false.

Try it online!

I downloaded a dictionary file, and the longest word I found was 11 letters -- tattletales

  • 1
    \$\begingroup\$ I think co? should be sufficient since sin will take care of the s :) Nice playing with /log?/! \$\endgroup\$
    – Sunny Pun
    Dec 4 '16 at 16:49
  • 1
    \$\begingroup\$ It doesn't say that it needs to be case insensitive (remove i), or that the single result has to make sense (remove one !) \$\endgroup\$ Dec 4 '16 at 18:19
  • \$\begingroup\$ Do you need i flag at very end since input is only a-z? \$\endgroup\$
    – Downgoat
    Dec 5 '16 at 15:04
  • \$\begingroup\$ You can make this simpler: -2: /^(s|sin?|co?|t|tan?|ln?|log?|e)+$/ or if you prefer: /^([celst]|sin?|co|tan?|ln|log?)+$/ \$\endgroup\$ Dec 5 '16 at 22:49
  • 1
    \$\begingroup\$ Enjoy your bounty! \$\endgroup\$ Dec 13 '16 at 17:03

JavaScript (ES6), 44 bytes


I think this is the shortest regex possible, but of course I may be wrong.


An obvious first place to start would be a regex that simply includes all options separately:


First, we can observe that cos can be formed from co and s, making it unnecessary:


Some of these, such as sin and si, can be combined by making the last letter optional:


This works because sin? matches si with or without an n on the end, thus covering both sin and si.

There seems to be a lot of n?s as well. What if we put them all together?


One more way to golf this would be to combine the remaining single-char options into a character range, but this comes out at the same length:


And that's how you golf a simple regex. I believe this is the shortest possible regex that matches every string correctly, but perhaps not. I will award a +100 bounty to anyone who manages to improve upon this regex.

  • \$\begingroup\$ The one that I used in my answer is sort of similar: ^(s|t|co?|(l|ta|si)n?|log?|e)+$ \$\endgroup\$ Dec 4 '16 at 21:23
  • \$\begingroup\$ Firstly, I count 44 bytes. Secondly, here's an alternate but longer solution: / /.test.bind(/^((si|ta|l)n?|co?|log?|[ste])+$/). \$\endgroup\$ Dec 4 '16 at 21:41
  • \$\begingroup\$ @ConorO'Brien Whoops, don't know how I miscounted that... \$\endgroup\$ Dec 4 '16 at 22:48
  • \$\begingroup\$ You can do a=/^((si|ta|l)n?|co?|log?|[ste])+$/;a.test for 42 bytes. I believe this is allowed, because a.test is an anonymous function. \$\endgroup\$ Dec 6 '16 at 1:39
  • \$\begingroup\$ @SeeOneRhino It is, but it's not really allowable because f=a.test doesn't work. I wonder if it's acceptable to call with the alternate name a.test though... \$\endgroup\$ Dec 6 '16 at 1:52

Pyth, 37 33 29 28 bytes

The code contains an unprintable character, so here is an xxd hexdump.

00000000: 737d 5173 4d5e 733c 5252 6336 2e22 6174  s}QsM^s<RRc6."at
00000010: 14d0 69ba 76f1 ac59 6422 346c            ..i.v..Yd"4l

Try it online.

Extremely Astronomically inefficient. The time and space complexity is O(16n) O(24n).


First, a Q is implicitly appended.

s}QsM^s<RRc6."…"4lQ     Implicit: Q = input
            ."…"        Generate "logsincostanlnee"
          c6            Split in 6 parts: ["log", "sin", "cos", "tan", "ln", "ee"]
         R      4       For each n from 0 to 3
       <R               Take the first n chars from each string
      s                 Flatten the results
                 lQ     Get length of input
     ^                  Take that Cartesian power of the list
   sM                   Join each resulting list
 }Q                     Check if the input is found
s                       Cast to integer
  • \$\begingroup\$ The OP has clarified; you don't need the s. \$\endgroup\$
    – Dennis
    Dec 5 '16 at 20:07

Jelly, 32 31 30 28 26 bytes


Outputs 0 if the word is typeable, 1 if not. Thanks to @JonathanAllan for golfing off 1 byte!

Try it online!

How it works

ŒṖw@€€“¡Ṡ[ẈKœịḲ-¢ȧ?-»’%3ḌẠ  Main link. Argument: s (string of lowercase letters)

ŒṖ                          Yield all partitions of s.
      “¡Ṡ[ẈKœịḲ-¢ȧ?-»       Yield "sine  logcostanln". Every third character
                            marks the start of a typeable word.
  w@€€                      Find the indices of all substrings in the partitions
                            in the string to the right (1-based, 0 if not found).
                     ’      Decrement. "Good" indices are now multiples of 3.
                      %3    Modulo 3. "Good" indices are mapped to 0, "bad"
                            indices are mapped to 1 or 2.
                        Ḍ   Convert from decimal to integer. A partition will
                            yield 0 iff all indices are "good".
                         Ạ  All; yield 0 if one or more integers are falsy (0), 1
                            if all integers are truthy (non-zero).

Brachylog, 33 bytes

Fixed a bug thanks to @Synoli.


Try it online!

Outputs true. if typeable or false. otherwise.


We try deconcatenations of the input until we find one for which all strings that we concatenate are a prefix of one of ["sin", "cos", "tan", "log", "lne", "eee].

~c                          A list of strings which when concatenated results in the Input
  :1a                       All strings of this list satisfy the predicate below:
,"sincostanloglneeee"@5           The list ["sin", "cos", "tan", "log", "lne", "eee"]
                       e          Take one element of that list
                        @[?       The input is a prefix of that element
  • \$\begingroup\$ Why the . after true? \$\endgroup\$
    – user41805
    Dec 4 '16 at 18:22
  • 1
    \$\begingroup\$ @KritixiLithos In SWI-Prolog when a query is true it prints true. and false. otherwise. i just reimplemented this: if the output is ignored (as it is here) and there is no writing to STDOUT, then it will print true. or false. depending on whether the main predicate succeeds or fails. It has a dot in SWI-Prolog because true. and false. are actually valid programs which always succeeds/always fails. \$\endgroup\$
    – Fatalize
    Dec 4 '16 at 18:26
  • \$\begingroup\$ How does this solution work without tan explicitly appearing in the list? \$\endgroup\$
    – Synoli
    Dec 11 '16 at 23:49
  • 2
    \$\begingroup\$ @Synoli It doesn't. I fixed it at the cost of 3 bytes, thanks. \$\endgroup\$
    – Fatalize
    Dec 12 '16 at 7:53

Perl 6,  60 50  44 bytes

first attempt (60)

put +?(get~~/^<{<sin cos tan ln log e>».&{|m:ex/^.+/}}>*$/)

translation of the Perl 5 answer (50)

put +?(get~~/^[s[in?]?|co?|t[an?]?|ln?|log?|e]*$/)

using -n switch (43+1)

put +?/^[s[in?]?|co?|t[an?]?|ln?|log?|e]*$/

The first ? converts the result to Boolean, and the first + converts that to a number (1 for True, 0 for False)


Mathematica, 101 bytes


It seems that the hard parts of this challenge are coming up with the shortest regex and choosing the most concise language to match the regex. I don't have anything to contribute to the former, and Mathematica isn't good candidate for the latter since you have to use StringMatchQ and RegularExpression. What I can do is answer your P.S.: is "tasteless" the longest word that you can type?

In[1]:= f=StringMatchQ[#,("sin"|"si"|"s"|"cos"|"co"|"c"|"tan"|"ta"|"t"|"ln"|"l"|"log"|"lo"|"e")..]&;

In[2]:= Select[EntityList@"Word",f@#[[2,1]]&][[All,2,1]]//SortBy[StringLength]//DeleteDuplicates
Out[2]= {c,e,l,s,t,cc,cl,el,et,lo,si,sl,ta,te,ccc,col,cos,cot,eel,ell,eta,etc,lee,let,log,lot,sec,see,set,sic,sin,sit,tae,tan,tat,tec,tee,cell,clog,clot,coco,cole,colt,coss,cost,cote,else,less,loco,loge,loll,lose,loss,lota,sect,seel,sell,sess,seta,sett,sill,silo,silt,sine,sise,siss,site,sloe,slog,slot,stet,taco,tact,tael,talc,tale,tall,tect,tell,test,cello,close,cosec,costa,cotan,eccle,elect,elsin,ettle,loess,lotte,secle,setee,since,sleet,stale,stall,state,steel,stele,tasse,taste,tatee,teest,telco,testa,tetel,tsine,cellco,closet,coleta,collet,coltan,cosine,cosset,costal,ecesis,estate,lessee,scelet,select,sellee,sestet,settee,settle,siesta,silole,stacte,stance,stasis,tallet,tallot,taslet,tassel,tasset,tattle,tectal,teetan,tellee,testee,tsetse,celesta,cessile,cocotte,collect,costate,ecolect,ectasis,electee,sessile,sinless,sitelet,statant,tassell,tastant,testate,coestate,colessee,colocolo,cosiness,costless,electant,lossless,sceletal,siletane,statelet,tactless,tallness,telltale,telocoel,coelostat,sissiness,stateless,tasteless,tattletale}

So "tattletale" seems to be the longest by one character.

  • \$\begingroup\$ Why is this non-competing? Does the function f you define not comply with the rules of the challenge? \$\endgroup\$
    – Dennis
    Dec 4 '16 at 17:23
  • \$\begingroup\$ No, it outputs True or False rather than a single character. \$\endgroup\$
    – ngenisis
    Dec 4 '16 at 17:25
  • \$\begingroup\$ Posts tagged with decision-problem are about determining True/False, so I think this is competing. \$\endgroup\$
    – FlipTack
    Dec 4 '16 at 17:29
  • \$\begingroup\$ Non-competing status is reserved for submissions that use a language or language feature that didn't exist or had a bug when the challenge was posted. \$\endgroup\$
    – Dennis
    Dec 4 '16 at 17:29
  • \$\begingroup\$ Fair enough. I edited my answer to have an actual solution. \$\endgroup\$
    – ngenisis
    Dec 4 '16 at 17:36

Wonder, 41 bytes



(!.(mstr"^(s|t|co?|(l|ta|si)n?|log?|e)+$")) "tasteless"

Totally misunderstood the question before, but now it's all fixed. Outputs F for match and T for no match.

Noncompeting, 35 bytes



(!.`^(s|t|co?|(l|ta|si)n?|log?|e)+$`) "tasteless"

This makes use of applicable regexes, which was implemented after this challenge.

  • 2
    \$\begingroup\$ From my understanding, you can only delete the last character in the calculator, which means n in not typable but sin and ln are. \$\endgroup\$
    – Sunny Pun
    Dec 4 '16 at 16:23
  • \$\begingroup\$ This regex detects sa as true \$\endgroup\$
    – user41805
    Dec 4 '16 at 16:27
  • 1
    \$\begingroup\$ This fails the test case got. \$\endgroup\$
    – Dennis
    Dec 4 '16 at 16:30
  • \$\begingroup\$ I believe it's fixed. \$\endgroup\$ Dec 4 '16 at 16:57
  • \$\begingroup\$ The ? make the sub expression docile; see rexegg.com/regex-quantifiers.html#cheat_sheet. But even making it greedy with ?? or possessive with ?+ doesn´t work for some reason (at least in PHP). coelostats triggers the trap (at lo and ta). \$\endgroup\$
    – Titus
    Dec 6 '16 at 12:19

Processing, 223 bytes

int d(String b){for(String p:"tan0log0sin0cos0ln0e".split("0"))if(p.startsWith(b))return 1;return 0;}

int l(String p){String b="";int t=1;for(char c:p.toCharArray()){b+=c;if(d(b)<1){b=c+"";t=d(b);}if(t<1)return t;}return t;}

Finally decided to do an answer without regex. To call the function, use l("tasteless");. Returns 0 for false and 1 for true.

Expanded code with explanation

int d(String b){
  for(String p:"tan0log0sin0cos0ln0e".split("0"))
      return 1;
  return 0;
//main function
int l(String p){
  String b="";
  int t=1;
  for(char c:p.toCharArray()){
    if(t<1)return t;
  return t;

Basically, we iterate over the given string, building up b char by char. We check using d() if any of the tan,log,... start with b. If it does, then it is valid. Else, we check if the char at that position is valid and we reset b. Now if it is invalid, 0 will be returned, or else it will still be valid. At the end, if the program hasn't already returned something, then return 1.

  • \$\begingroup\$ Can't the d function return a bool? \$\endgroup\$ Dec 5 '16 at 13:55
  • \$\begingroup\$ @RomanGräf It is more bytes to use boolean than int. Also true and false require more bytes than 1 and 0 \$\endgroup\$
    – user41805
    Dec 5 '16 at 14:03

Scala, 49 bytes


Returns true if the given string matches the regex, false otherwise.


Python 3, 154 bytes

while r:
 for s in'sin,cos,tan,log,ln,co,lo,si,ta,s,c,t,l,e'.split(','):
  if i.startswith(s):r=i=i.replace(s,'',1);break

Try it online!

  • 1
    \$\begingroup\$ You might need to check indentation, I had to edit the code to make it work \$\endgroup\$
    – george
    Dec 5 '16 at 10:02
  • \$\begingroup\$ @george, weird, I tried in IDLE and the online compiler, and both seem to work \$\endgroup\$
    – Henke
    Dec 5 '16 at 17:38

Python 3, 149 130 bytes

for a in 'tan,sin,cos,log,si,co,ta,lo,lo,ln,s,c,t,l,e'.split(','):
    if a in i:
print(not i)

edit #1: shaved 19 bytes using @Henke solution


Python 2, 124 bytes

f=lambda w:any(f(w[len(s):])if w[:len(s)]==s else 0for s in'sin,cos,tan,log,ln,co,lo,si,ta,s,c,t,l,e'.split(','))if w else 1

PHP, 60 bytes


regex stolen from ETHproductions:
takes input from command line argument; prints 1 for typable, 0 for not typeable.

older versions, 75 73 69 bytes


replaces all possible words with empty string, returns the result, negates.


splits input by regex matches. Flag 1 stands for PREG_SPLIT_NO_EMPTY and tells preg_split to only return non-empty results. If input is typable, preg_split will only have empty results, so it will return an empty array, which is falsy. ! negates the result.

Both versions take input from command line argument
and print 1 if result is empty (input is typable), else nothing.

Packing the regex using ? does not work here; it renders the expressions ungreedy; probably due to backtracking. And the order of the alternatives is important: ta has to stand before t or the engine will stop matching when it finds t.

I found a quantifier cheat sheet, thought ?? or ?+ might help; but they did not work for me.


Java 8, 55 bytes

s->return s.matches("^((si|ta|l)n?|co?|log?|[ste])+$");

Disclamer: I used ETHproductions' regex because it was many bytes shorter than mine. Full credit on the Regex to him. What I did was add 24 bytes to make it a Java function.

Returns false if the word did not fit into the Regex, else true.


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.