𝖧ello all, I hope this finds you well.

There are 118 elements on the Periodic table at the moment, each one corresponds to the number of protons in an atom's nuclei.

Each element also has a 'symbol'. Hydrogen has 'H', Helium has 'He' and so on. I want to know about these!


Given 1 string as input, output true if the string is present as a symbol on the periodic table. Output false if not.

The string is case sensitive. While He is a valid symbol, he is not.

For reference, here are the elements that are valid symbols for this challenge (from wikipedia): enter image description here

That is, if the string is any one of the elements in this list, output 'true':


And, Alphabetically indexed:


This is a classic code golf, so be sure to reduce the number of bytes you use in any way possible.

Good luck~!

  • 3
    \$\begingroup\$ Is the input string guaranteed to match /[a-zA-Z]{1,2}/? \$\endgroup\$
    – Arnauld
    Commented Aug 28, 2023 at 21:48
  • 4
    \$\begingroup\$ What are the test cases? \$\endgroup\$
    – Someone
    Commented Aug 28, 2023 at 21:59
  • 4
    \$\begingroup\$ @Arnauld it is not. the only guarantee is that the string is valid for whatever language you're using \$\endgroup\$
    – tuskiomi
    Commented Aug 28, 2023 at 22:55
  • 1
    \$\begingroup\$ @tuskiomi Well, technically, several elements were made by the government ;) \$\endgroup\$
    – DLosc
    Commented Aug 29, 2023 at 22:02
  • \$\begingroup\$ Related: Print all 2 letter Scrabble Words \$\endgroup\$
    – xnor
    Commented Aug 30, 2023 at 1:37

19 Answers 19


Factor + periodic-table, 22 17 bytes

[ elements key? ]

Attempt This Online!

Factor has a built in periodic table (with all 118 elements and no typos; I checked :D).


Retina 0.8.2, 197 195 bytes


Try it online! Link includes test cases. Explanation: Grouping by last letter is slightly shorter than grouping by first letter. I also saved three bytes by handling Cd, Co, Md, Mo, Nd, No, Pd and Po together, Ba, Bh, Na, Nh, Ra, Rh, Ta and Th together, and Al, Am, Cl, Cm, Fl, Fm, Tl and Tm together. (Grouping by last letter didn't seem to offer the same opportunities.) Edit: Saved 2 bytes thanks to @DidierL by grouping B, Br, C, Cr, F, Fr, I, Ir, K, Kr, P, Pr, S and Sr together.

Edit: Added Be, which @JonathanAllen pointed out was missing from the table in the question.

  • 1
    \$\begingroup\$ I think you can spare 2 more bytes by splitting [ABCEFIKLPSZ]r into [BCFIKPS]r?|[AELZ]r, and removing BCFIKPS from the first character set. \$\endgroup\$
    – Didier L
    Commented Aug 31, 2023 at 23:31

JavaScript (Node.js), 186 bytes

Returns 0 or 1.


Try it online!

All truthy inputs / Random falsy inputs


s =>                    // s = input string
parseInt(               // parse as base-36:
  "2cjns/5ogz/.../5yww" //   lookup string
  .split`/`             //   turned into an array
  [(                    //
    [a, b, c] =         //   a, b, c = ASCII codes of the first
      Buffer(s),        //             three characters in s
    a - 65              //   use a - 65 as the lookup index
  )] || 0,              //   force to 0 if there's no entry
  36                    //
) >> b &                // right-shift by b positions (mod 32)
!(                      // test the least significant bit
  c |                   // make sure that s has either 1 or 2 chars.
  b < 97 | b > 122      // and that the 2nd one (if present) is a
)                       // lowercase letter
  • 1
    \$\begingroup\$ Is that basically a custom encoding whose decoder is .replace(/./g,c=>"1".padEnd(Buffer(c)[0]-31))[parseInt(s,36)*527%1287]? Was it arrived using a separate program? \$\endgroup\$
    – Jonah
    Commented Aug 28, 2023 at 22:35
  • 4
    \$\begingroup\$ @Jonah This encodes a lookup binary string (with many 0's) giving the answer for each possible input [a-z]{1,2} interpreted as a base-36 value. \$\endgroup\$
    – Arnauld
    Commented Aug 28, 2023 at 22:46
  • \$\begingroup\$ (NB: the above comment applies to my previous version) \$\endgroup\$
    – Arnauld
    Commented Aug 29, 2023 at 8:34

Wolfram Language (Mathematica), 50 bytes


Uses the inevitable builtin. Don't try it online, since it requires access to Mathematica's data repository that TIO doesn't have :( On the plus side, all of the nested argument precedences worked out so that the ~ syntax could be used without brackets.


Nibbles, 98.5 97.5 bytes (195 nibbles)

Edit: -2 nibbles by changing the encoding

?+! |_\$u .`/~`=`D-28\$N |+$\$! ~.@:@\$a $ 1e0ffdd0810caa7a28e383c93c330770433251ee362b67eb4b57b2c6f2899d4742d379353a3791767afb7dd86bbf684e52506db285eb7e59af343e632802eec0bde3135659c1618936c003d96bbca

Attempt This Online!

Similar 'build the element symbols using the lists of second letters for each first letter' approach to Neil's Charcoal answer.

How? (original 98.5-byte version):

?++! `%`D-26"j" |@\$u ~.$%:_$~ $ 
   !                                # zip together
       `D-26                        #  the hex data 243d...
                                    #  decoded using base 26 to " abc...y"
     `%     "j"                     #  and split on the letter "j"
                                    # with
                |@\$u               #  uppercase letters
                                    #  (printable ASCII filtered for uppercase)
                      ~             # by
                       .$           #  mapping over each group of lowercase letters
                          :_$       #  appending each to the uppercase letter 
                         %   ~      #  and removing spaces
 ++                                 # flatten to a list of element-strings
?                              $    # and find the index of the input
                                    # (or zero if not found)

R >=4.1, 235 232 224 221 220 bytes

We build all valid element names by "overloading" the / operator with the function strsplit, then unpacking the string of single-character names. We unpack another string with all capital letters except J and Q, then paste them to the unpacked second characters of the two-character names.

I am sure it's very golfable because I am bad at this.

edit: realized I can remove UVW from singletons.
edit2: -8 bytes due to Giuseppe tricks
edit3: mapply can be drop-in replaced with its simplified wrapper Map, thanks again Giuseppe edit4: another -1 byte from Giuseppe indexing trick


Attempt this Online

  • 2
    \$\begingroup\$ Btw, you can use Attempt This Online (which currently is running version 4.3.1), which is basically just a newer version of Try It Online. \$\endgroup\$
    – The Thonnu
    Commented Aug 29, 2023 at 19:10
  • 1
    \$\begingroup\$ this is 8 bytes shorter; I'm not sure if this is the best approach, though. \$\endgroup\$
    – Giuseppe
    Commented Aug 29, 2023 at 19:19
  • 1
    \$\begingroup\$ uses / as an alias for strsplit and use el(strsplit(...,...)) instead of strsplit(...,...)[[1]] \$\endgroup\$
    – Giuseppe
    Commented Aug 29, 2023 at 19:21
  • 1
    \$\begingroup\$ @JDL strsplit always returns a list, which is making this tricky. You could use any(Map('%in%',x,list_of_element_symbols)) but that's longer than unlist; aliasing Map won't help since it's a length-3 function name used twice. \$\endgroup\$
    – Giuseppe
    Commented Aug 31, 2023 at 2:00
  • 2
    \$\begingroup\$ for some kinds of lists, there are more efficient ways of unlisting --- el(), `t(t(...))`` and so on. but if they don't work, fair enough --- this just set my spidey-sense tingling for some reason! \$\endgroup\$
    – JDL
    Commented Aug 31, 2023 at 8:25

Ruby, 158 bytes


Attempt This Online!


Thunno 2, 99 bytes

»ṘẋḄæØoṖßYp’ɲ»13BkAd×J“UẹÐċḷṘtƁMƓẠÇ|huṗ½ñ{ɓ[ṇẊ§ ?bx€Żcb0ḳßƝḄƤİỵṁ×cj"D³¿Œ_ɼỴıR9?ñ’Þ@YX§1OçG¦ʂŻ“Z€JwƇ

Try it online!

Inspired by Neil's Charcoal answer.


The idea is to construct the first and second letter strings separately, and then zip them together. We can sort the first letters in alphabetical order, and then multiply the alphabet with a list of numbers to get the whole string. There are 8 As, 7 Bs, 12 Cs, etc. So, we use the list [8, 7, 12, ...]. Then, we use base-255 compression to get the string of second letters, replacing it with a space where the symbol is only one letter, then after zipping we can remove the whitespace. Finally, after we've constructed the list, we can check if it contains the input.

»...»13BkAd×J“...“Z€JwƇ  # Implicit input
»...»13B                 # Compressed list [8,7,12,3,3,5,3,6,3,0,2,5,6,9,3,9,0,8,9,9,1,1,1,1,2,2]
        kAd×J            # Multiply elementwise with the uppercase alphabet - the first letters
             “...“       # Compressed string of second letters, or spaces where N/A
                  Z€J    # Zip with the first letters and join each pair into a string
                     w   # Remove whitespace (the space fillers in the second letters)
                      Ƈ  # Is the input in this list?
                         # Implicit output

Python 3,  222 219  212 bytes

-3 thanks to bsoelch! (Avoiding enumerate.)
-7 thanks to xnor! (Use the direct functional reference [...].count.)

[chr(i+65)+r[r>'y':]for i in range(26)for r in'cglmrstu,zaehikr,zadeflnmorsu,bsy,rsu,zelmr,ade,zefgos,znr,,zr,airuv,cdgnot,zabdehiop,zgs,zabdmortu,,abefghnu,zbcegimnr,abcehilms,z,z,z,e,zb,nr'.split(',')[i]].count

(Beryllium is included at a cost of 1 byte)

Try it online! Or see the test-suite.

Beatable with a hashing approach or even regex? (Edit or golfing bsoelch's ...until they golfed mine! ;p)

  • 1
    \$\begingroup\$ You can split enumerate in index and array access to save 3 bytes: lambda s:s in[chr(i+65)+r[r>'y':]for i in range(26)for r in'cglmrstu,zaehikr,zadeflnmorsu,bsy,rsu,zelmr,ade,zefgos,znr,,zr,airuv,cdgnot,zabdehiop,zgs,zabdmortu,,abefghnu,zbcegimnr,abcehilms,z,z,z,e,zb,nr'.split(',')[i]] tio \$\endgroup\$
    – bsoelch
    Commented Aug 29, 2023 at 10:50
  • \$\begingroup\$ @bsoelch nice, and there I was wondering how I could incorporate a walrus somehow! Thanks. \$\endgroup\$ Commented Aug 29, 2023 at 11:48
  • \$\begingroup\$ I think you can do [...].count to avoid a lambda, assuming 0/1 output is ok \$\endgroup\$
    – xnor
    Commented Aug 30, 2023 at 1:38
  • \$\begingroup\$ @xnor I observed that .__contains__ was equal in length but didn't think to use .count - should be fine, as it's a decision_problem, thanks! \$\endgroup\$ Commented Aug 30, 2023 at 11:11

Python, 210 bytes

-10 bytes, thanks to Jonathan Allan
-11 bytes, thanks to xnor

lambda s:s in{*"BCFHIKNOPSUVWY"}or"A"<s<"["<s[1:]in[*"cglmrstu,aehikr,adeflnmorsu,bsy,rsu,emlr,ade,egfos,nr,,r,airuv,cdgnot,abdeihop,gs,badormtu,,abefghnu,bcmgeinr,abcehslim,,,,e,b,nr".split(",")[ord(s[0])-65]]

Attempt This Online!


First check for one character element names.

If the name has two characters check if the first is between A and [ (one after Z) in lexicographical order. Then check if the second character is a second character of an element name starting with the first character

Python, 362 bytes

the naive approach

lambda s:s in"Ac,Ag,Al,Am,Ar,As,At,Au,Ba,B,Bh,Bi,Bk,Br,Ca,Cd,C,Ce,Cf,Cl,Cn,Cm,Co,Cr,Cs,Cu,Ds,Db,Dy,Er,Es,Eu,Fm,Fl,F,Fe,Fr,Ga,Gd,Ge,H,He,Hg,Hf,Ho,Hs,I,In,Ir,K,Kr,La,Li,Lr,Lv,Lu,Md,Mg,Mn,Mt,Mo,Mc,N,Na,Nb,Nd,Ne,Ni,Nh,No,Np,O,Og,Os,Pb,P,Pa,Pd,Po,Pr,Pm,Pt,Pu,Ra,Rb,Re,Rf,Rg,Rh,Rn,Ru,S,Sb,Sc,Sm,Sg,Se,Si,Sn,Sr,Ta,Tb,Tc,Te,Th,Ts,Tl,Ti,Tm,W,U,V,Xe,Y,Yb,Zn,Zr".split(",")

Attempt This Online!

  • \$\begingroup\$ in{*"B...") saves three and some logical shortcutting saves another seven. Adding in Beryllium which was missed by OP costs one byte. lambda s:s in{*"BCFHIKNOPSUVWY"}or"A"<s<"["*(len(s)==2)and s[1]in"cglmrstu,aehikr,adeflnmorsu,bsy,rsu,emlr,ade,egfos,nr,,r,airuv,cdgnot,abdeihop,gs,badormtu,,abefghnu,bcmgeinr,abcehslim,,,,e,b,nr".split(",")[ord(s[0])-65] \$\endgroup\$ Commented Aug 29, 2023 at 2:08
  • \$\begingroup\$ 210 bytes: lambda s:s in{*"BCFHIKNOPSUVWY"}or"A"<s<"["<s[1:]in[*"cglmrstu,aehikr,adeflnmorsu,bsy,rsu,emlr,ade,egfos,nr,,r,airuv,cdgnot,abdeihop,gs,badormtu,,abefghnu,bcmgeinr,abcehslim,,,,e,b,nr".split(",")[ord(s[0])-65]] \$\endgroup\$
    – xnor
    Commented Sep 1, 2023 at 6:57

05AB1E, 100 bytes


Try it online!

Same as my Thunno 2 answer.

-1 thanks to @KevinCruijssen


•...•13вAuS×J.•...•ø€áIå  # Implicit input
•...•13в                  # Compressed list [8,7,12,3,3,5,3,6,3,0,2,5,6,9,3,9,0,8,9,9,1,1,1,1,2,2]
        AuS×J             # Multiply elementwise with the uppercase alphabet - the first letters
             .•...•       # Compressed string of second letters, or spaces where N/A
                   ø      # Zip with the first letters and join each pair into a string
                    ۇ    # Remove whitespace (the space fillers in the second letters)
                      Iå  # Is the input in this list?
                          # Implicit output
  • \$\begingroup\$ ðδÜ can be ðм or €á to save a byte. \$\endgroup\$ Commented Sep 8, 2023 at 9:16
  • \$\begingroup\$ @KevinCruijssen thanks, updated \$\endgroup\$
    – The Thonnu
    Commented Sep 10, 2023 at 9:17

Charcoal, 120 bytes

№⁻E”|«↓‹℅Zy⊗⌈↗⁷◧⟦π@0\`‽◧~H≕' t?¹6´↗T?ⅉς6σ”⁺駔&⌊↧\`rfV~⍘ROB;ü⌈ê↙⌕Xhk~& №E⪪DTN¿O-·⁶‹6n×⊟3✳∧Ap|λXⅉω⪫¦⁻⊟»lC↓×;!"B⊘ⅈêα⊗◨·²”κjS

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for an element, nothing if not. Explanation:

№                   Count of
                  S Input string in
   ”...”            Compressed string of first characters
  E                 Map over characters
         ι          Current character
        ⁺           Concatenated with
           ”...”    Compressed string of second characters
          §         Indexed by
                κ   Current index
 ⁻               j  Remove all `j`s from all strings
                    Implicitly print

The string of two-characters elements is 151 bytes compressed. I tried uppercasing the string which reduces it to only 127 bytes, with the decoding logic resulting in a 155 byte solution, but then I hit on the idea of compressing the first and last characters separately. I then saved a final two bytes by compressing the single-element names with a trailing j which I then remove afterwards.


Ruby, 207 190 192 bytes

"&$&%$%&$$&amp;%$$%	'($($$$3'&amp;$%*6&amp;$$)$$$&amp;$%44)@$%7*$(6&amp;$G$$+'B'k6+,&$4$&*$(4$%$&$)$>/5$%,%&%$W$&$$$)*4$%%%'$'6$$%&$&$)\xA5DS'".bytes{|i|k||=n==(j+=i>9?i-35:338).to_s(36).capitalize}

Try it online!

For some reason, TIO.run pastes the & characters as &amp; in the output formatted for this website, but the code at TIO.run shows them as a single character.

Produces all valid elements by incrementing j according to each term in the magic string and converting the result to a base 36 number. The increment of j is based on ASCII CODE - 35 to avoid having " or # in the string.

Single-letter elements are first in this order, and there is a big jump of 338 from Y to Ac which requires special handling as it won't fit in a single byte. The jump is encoded as a TAB=ASCII 9.

2 bytes added to make it work with Be and S

  • \$\begingroup\$ Initialize your array with ->n,*a{ for -2. \$\endgroup\$
    – Value Ink
    Commented Aug 29, 2023 at 5:17
  • \$\begingroup\$ Actually, you can initialize it as a hash with ->n,**a, populate with a[(j+=j==34?338:i-34).to_s(36).capitalize]=1, and return a[n] to save 1 more. It won't be literal true/false, but it's truthy/falsy. \$\endgroup\$
    – Value Ink
    Commented Aug 29, 2023 at 5:37
  • \$\begingroup\$ @ValueInk thanks for the tips. It was shorter in the end to get rid of the array and just test each value as it is produced. Harder to test the code that way, though. \$\endgroup\$ Commented Aug 29, 2023 at 19:29
  • \$\begingroup\$ Running your code against dingledooper's test battery on their answer shows an incorrect answer for Beryllium Be, and modifying it to check single-letter elements also shows an incorrect answer for Sulfur S. (The TIO/ATO link demonstrating this is too long for this comment.) \$\endgroup\$
    – Value Ink
    Commented Aug 29, 2023 at 20:40
  • 1
    \$\begingroup\$ @ValueInk Be was missing from the original question and has been edited in later. Not sure why I missed S, it's missing from the source code I used to make the magic string. I will fix it ASAP - it will add 2 bytes. \$\endgroup\$ Commented Aug 29, 2023 at 21:05

Python, 271 bytes

import re



PowerShell Core, 257 bytes


Try it online!

A naive approach, cin stands for case sensitive in and csplit for case sensitive split.

+2 bytes for Beryllium


Python, 210 bytes

lambda s:1/(s in{*"BCFHIKNOPSUVWY"}or"A"<s*(s[1]in"cglmrstu,aehikr,adeflnmorsu,bsy,rsu,emlr,ade,egfos,nr,,r,airuv,cdgnot,abdeihop,gs,badormtu,,abefghnu,bcmgeinr,abcehslim,,,,e,b,nr".split(",")[ord(s[::2])-65]))

Many thanks to bsoelch's python answer!

I refactored it so it returns 1.0 if the input is an element and raises an Exception if it isn't.

Interesting notes:

  1. The * is used as a boolean AND.
  2. s[::2] produces every second element, and ord raises an Exception if its argument is longer than one character. So, this expression filters out anything 3 chars or longer

Attempt This Online!


C (GCC), 276 274 bytes

-2 bytes thanks to @ceilingcat


Attempt This Online!


Pascal, 352 bytes

This function requires a processor supporting features of ISO standard 10206 “Extended Pascal”, in particular the string schema data type and index string search function.

type t=string(3);function f(s:t):Boolean;begin case length(s)of 1:f:=index('BCFHIKNOPSUVWY',s)>0;2:f:=odd(index('AcAgAlAmArAsAtAuBaBeBhBiBkBrCaCdCeCfClCmCnCoCrCsCuDbDsDyErEsEuFeFlFmFrGaGdGeHeHfHgHoHsInIrKrLaLiLrLuLvMcMdMgMnMoMtNaNbNdNeNhNiNoNpOgOsPaPbPdPmPoPrPtPuRaRbReRfRgRhRnRuSbScSeSgSiSmSnSrTaTbTcTeThTiTlTmTsXeYbZnZr',s));otherwise f:=6=9 end end;


    { A schema data type `string` is an Extended Pascal extension.
      Here we discriminate `string` to have (at least) a capacity
      exceeding one character than the longest abbreviation. }
    tripleCharacter = string(3);

{ NB: When calling with a string literal longer than three characters,
      the extra character are silently clipped. }
function isElementAbbreviation(protected sample: tripleCharacter): Boolean;
        single = 'BCFHIKNOPSUVWY';
        double = 'AcAgAlAmArAsAtAuBaBeBhBiBkBrCaCdCeCfClCmCnCoCrCsCu' +
                 'DbDsDyErEsEuFeFlFmFrGaGdGeHeHfHgHoHsInIrKrLaLi' +
                 'LrLuLvMcMdMgMnMoMtNaNbNdNeNhNiNoNpOgOs' +
                 'PaPbPdPmPoPrPtPuRaRbReRfRgRhRnRuSbScSeSgSiSmSnSr' +
        case length(sample) of
                { In Pascal `string`s indices are 1-based.
                  `index` returns `0` if nothing was found. }
                isElementAbbreviation := index(single, sample) > 0;
                { Do not match, for example, `'cA'`. }
                isElementAbbreviation := odd(index(double, sample));
                isElementAbbreviation := false;

Python, 229 bytes

Thanks to @Neil for the regex - :)

import re;bool(re.match("([HNOUVWY]|[CGLP]a|[DNPRSTY]b|[AMST]c|[CMNP][do]|Gd|[BCFGHNRSTX]e|[CHR]f|[AHMORS]g|[BNRT][ah]|[BLNST]i|Bk|[ACFT][lm]|Pm|Sm|[CIMRSZ]n|Ho|Np|[AELZ]r|[BCFIKPS]r?|[ACDEHOT]s|[AMP]t|[ACELPR]u|Lv|Dy)",input()))

...go brr


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.