An elementary challenge

This challenge is inspired by this Oliver Sacks quote:

“At 11, I could say ‘I am sodium’ (Element 11), and now at 79, I am gold.” ― Oliver Sacks

I want you you find numbers in a string and replace them with their corresponding elements' symbols. (1 is H, 2 is He, 3 is Li, etc.) There are a few rules to follow:

• Single and double digits get replaced with their corresponding elements as normal. Ignore 0s at the start of numbers. If there are just 0s in a number, ignore it. E.g. 1 01 10 0 00 becomes H H Ne 0 00
• More than 2 digits together get divided into groups of 2. An odd number of digits should have the extra single digit at the end. E.g. 0153 5301 153 would become HI IH PLi Because of this rule, you will only need to know the elements from 1 to 99
• Numbers shall be treated the same no matter what characters surround them and commas and decimal points are not parts of numbers. P90X 42,800 3.14159 would become PThX Mo,Hg0 Li.SiPF

Example Inputs/Outputs (I/O):

I: 32289216
O: GeNiUS

I: J08017 5811
O: JOHN CeNa

I: M18227 0592tt10r
O: MArTiN BUttNer

I: De072816
O: DeNNiS

I: D088r1907085
O: DOOrKNOB

I: 13ex A.
O: Alex A.


Input will be in the closest format to a string that your language has.

A periodic table for reference:

This is , so your program will be scored in bytes.

• John Cena is a moderator at PPCG? ;-) Commented Oct 28, 2015 at 0:27
• Please give a warm welcome to our new moderator JOHN CENA music and airhorns start blaring Commented Oct 29, 2015 at 1:58
• instantcena.com Commented Oct 29, 2015 at 12:54

Mathematica, 9694 89 bytes

StringReplace[#,n:DigitCharacter~Repeated~2/;(d=FromDigits@n)>0:>d~ElementData~"Symbol"]&


Mma has several datasets...

• Well of course a built-in dataset will beat a 139-byte compressed string. ;) Commented Oct 28, 2015 at 14:08
• @ETHproductions I'm just surprised that this has been the shortest answer for 9 hours. Usually, this place is reserved for CJam and Pyth :D Commented Oct 28, 2015 at 20:57
• Well, let's see: to beat 89 bytes, one would either need to super-condense the 184 necessary alphabetic characters—AND create a program to decode it—in under 89 bytes (very very unlikely), OR find another language which has a built-in dataset of the proper elements (neither CJam or Pyth). So this will likely end up being the winner. Commented Oct 29, 2015 at 15:14

JavaScript (ES6), 202 bytes

x=>x.replace(/\d\d?/g,y=>+y?btoa(139 bytes; see hexdump below).match(/[A-Z][a-z]?/g)[+y]:y)


The omitted string contains unprintable characters, so here is a (hopefully reversible) hexdump:

00000000: 0071 de2e 205e 0423 4e14 d78d 68c8 0095 288f  .qÞ. ^.#N.×.hÈ..(.
00000012: 4829 40ac a09a 49c4 e254 2acc 9c57 82a0 d882  H)@¬ .IÄâT*Ì.W. Ø.
00000024: b999 c668 6780 b127 81ac aad1 6d2a d866 b35b  ¹.Æhg.±'.¬ªÑm*Øf³[
00000036: 3284 dc46 e461 3dd0 2009 d227 4a74 9b4d e217  2.ÜFäa=Ð .Ò'Jt.Mâ.
00000048: 782b 0168 b682 78fa cd74 f992 984b 8675 36c3  x+.h¶.xúÍtù..K.u6Ã
0000005a: c87a 04ad 3998 6cbb 877d 3696 45e3 ac22 b3ed  Èz..­9.l».}6.Eã¬"³í
0000006c: 02e1 e04e 53db 0623 e802 d467 16b4 5a01 c4e1  .áàNSÛ.#è.Ôg.´Z.Äá
0000007e: 3da5 0da4 fb80 9829 8190 27c4 b0              =¥.¤û..)..'Ä°


The technique here was to put all the element abbreviations in one string, separated by nothing—that's what the second regex /[A-Z][a-z]?/g is for; it matches each capital letter, optionally followed by a lowercase letter. The first regex, /\d\d?/g, matches each set of 2 (or 1) digits in the input, so this replaces each set of digits N with the element at index N in the decompressed, matched string.

Here's the original string, if anyone else would like to use it: (the A's at the ends are fillers)

AHHeLiBeBCNOFNeNaMgAlSiPSClArKCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsA


Questions and suggestions welcome!

• What about Uus and Uuo? Commented Oct 28, 2015 at 2:42
• @CᴏɴᴏʀO'Bʀɪᴇɴ - The question only requires up to element 99, which is Einsteinium (Es), so the unconfirmed elements (which therefore don't have final names, and are written with three characters) don't factor in at all. Commented Oct 28, 2015 at 5:19
• Nice. I think you don't need the check +y?...:... as you are replacing digit groups Commented Oct 28, 2015 at 7:05
• @edc65 Thanks. One of the rules is that any 00's in the input need to be unchanged, so that check is necessary. Commented Oct 28, 2015 at 13:00
• now I see. Still you can use [y] instead of [+y] and save 1 byte Commented Oct 29, 2015 at 7:09

Python 3, 278 285 bytes

import re;f=lambda a:re.sub('(?!00)\d\d?',lambda m:'0HHLBBCNOFNNMASPSCAKCSTVCMFCNCZGGASBKRSYZNMTRRPACISSTIXCBLCPNPSEGTDHETYLHTWROIPAHTPBPARFRATPUNPACBCE  eie     eagli  lr aci rneoiunaeserrbr rbocuhdgdnnbe esaaerdmmudbyormbufa esrtuglbiotnracha pummkfs'[int(m.group())::100].strip(),a)


Test cases:

>>> f('32289216')
'GeNiUS'
>>> f('J08017 5811')
'JOHN CeNa'
>>> f('M18227 0592tt10r')
'MArTiN BUttNer'
>>> f('De072816')
'DeNNiS'
>>> f('D088r1907085')
'DOOrKNOB'
>>> f('13ex A.')
'Alex A.'
>>> f('P90X 42,800 3.14159')
'PThX Mo,Hg0 Li.SiPF'
>>> f('1 01 10 0 00')
'H H Ne 0 00'

• f('P90X 42,800 3.14159') returns 'PThX Mo,Hgs Li.SiPF' instead of 'PThX Mo,Hg0 Li.SiPF' and f('1 01 10 0 00') returns 'H H Ne s s' instead of 'H H Ne 0 00'. By the way, I just used your extended slicing approach in my Python 2 solution. Thanks!
– cr3
Commented Oct 29, 2015 at 1:26
• @cr3: Fixed 0 and 00. Commented Oct 29, 2015 at 2:56
• nice, you beat me by 19 bytes!
– cr3
Commented Oct 29, 2015 at 3:29

Python 2, 312 304 bytes

import re
f=lambda a:''.join([j or'0HHLBBCNOFNNMASPSCAKCSTVCMFCNCZGGASBKRSYZNMTRRPACISSTIXCBLCPNPSEGTDHETYLHTWROIPAHTPBPARFRATPUNPACBCE0 eie     eagli  lr aci rneoiunaeserrbr rbocuhdgdnnbe esaaerdmmudbyormbufa esrtuglbiotnracha pummkfs'[int(i)::100].strip() for i,j in re.findall('(\d\d|[1-9])|(.)',a)])


This one creates a function f which takes a string of numbers as argument and returns the corresponding string with element symbols replaced.

The function iterates over strings of one to two digits ('1', '01', '10', '00' but not '0') or one character ('a', '0' but not '1'). In the case of digits, the string is converted to an integer and looked up in a concatenated string of element symbols where each symbol is padded to two characters. In the case of characters, the string is simply used without lookup.

The tests for each example in the question all pass:

assert f('P90X 42,800 3.14159') == 'PThX Mo,Hg0 Li.SiPF'
assert f('1 01 10 0 00') == 'H H Ne 0 00'
assert f('0153 5301 153') == 'HI IH PLi'
assert f('32289216') == 'GeNiUS'
assert f('J08017 5811') == 'JOHN CeNa'
assert f('M18227 0592tt10r') == 'MArTiN BUttNer'
assert f('De072816') == 'DeNNiS'
assert f('D088r1907085') == 'DOOrKNOB'
assert f('13ex A.') == 'Alex A.'