# Periodic Table of Elements - Code Golf

Based on Practical Golf - US States

Your task is to find the abbreviation (symbol) of an element given the element name, up to and including ununoctium (118). Use the periodic table on Wikipedia.

Thanks to squeamish ossifrage, you can find a full list of elements to abbreviations at http://pastebin.com/DNZMWmuf.

You may not use any external resources. In addition, you may not use any built-in data specifically about the elements of the periodic table. Standard loopholes apply.

Input

Input may be from stdin, file, prompt, input etc.

Input Format:

All of the following are valid inputs:

Carbon
carbon
CARBON
cArBOn


Essentially, the element name - case insensitive.

You do not have to handle misspellings or any invalid element name. Invalid input is undefined behavior.

Output:

The symbol for the element. The first character must be capitalized and the rest must be lowercase.

Example output: C

Test cases:

Carbon -> C
NiTROGen -> N
Sodium -> Na
Gold -> Au
Silver -> Ag
Tin -> Sn


There are many more elements than states, so I expect it to be harder to find a general rule for these.

This is code golf. Shortest code wins!

• @squeamishossifrage Thanks. Both versions ("sulphur" and "sulfur") are acceptable. Your program does not have to handle both, however, only one. – soktinpk Oct 6 '14 at 20:58
• ...impossible to do with regexes. You got us good. – Josiah Winslow Oct 6 '14 at 22:30
• @Xrylite Try reading the rules: "Input ... the element name - case insensitive ... Output ... The first character must be capitalized and the rest must be lowercase". – Jim Balter Oct 7 '14 at 5:30
• What about proper spelling (Aluminium) versus US spelling (Aluminum) ? – Paul R Oct 7 '14 at 9:40
• @codebreaker Yes, if the input is not valid, your program may crash, hang, print Au, or whatever you want. @Paul R If there are many ways to spell an element (e.g. sulphur vs sulfur or aluminium vs aluminum) use whichever makes your program shorter. You do not have to handle both cases. – soktinpk Oct 7 '14 at 21:21

# CJam, 337297293232220201 200 bytes

leu:E2f^3b2+4%_"53N5903CVCT4":i3/=~Ef+b\%]53b"gØâ^ÃP·^À4Î¾^ß^E5^W^Ma{áª^B¤±´oòæ»^XÊQÑ»4Å¾DÙÝòÙ 0^ÝþKa6^Ó£,Ûkû¥¡ùh^E"256b7b6a/0a3**<)5md@5a/,(" ¬^GH/N¿·%^U^RU1²Bd
òë^Ð¼~í^ÌéáU"256b25b'Af+2/='J-'Q/"UU"*\)_5=)*E%2<?(\el


The above code uses caret notation, since it contains control characters.

At the cost of 24 additional bytes (for a total of 224), those characters can be avoided.

leu:E2f^3b2+4%_"53N5903CVCT4":i3/=~Ef+b\%]53b
$cksum elements.cjam 952664534 200 elements.cjam$ for e in Carbon NiTROGen Sodium Gold Silver Tin; do LANG=en_US cjam elements.cjam <<< $e; echo; done C N Na Au Ag Sn  ### How it works The first step is to read the element name from STDIN and apply a rather elaborated hash function, which maps all element names in the range [0, 225]: l eu :E " Read a line from STDIN, convert to uppercase and save in E. "; 2 f^ " XOR each character code with 2. "; 3 b " Convert to integer; consider the resulting array a base 3 number. "; 2 + 4 % " Add 2 and take the result modulo 4. Result: R "; "53N5903CVCT4":i " Push [53 51 78 53 57 48 51 67 86 67 84 52]. "; 3 / = " Retrieve the chunk of length 3 that corresponds to R. Result: C "; ~ E f+ " Add C[2] to all character codes of E. "; b " Convert to integer; consider the resulting array a base C[1] number. "; \ % " Take the integer modulo C[0]. Result: M "; ] 53 b " Push H := 53 * R + M. ";  Many element symbols are formed by the first and second, first and third, first and fourth, first and fifth or first and tenth (which is just the first) character of the element's English name. We are going to represent these elements by numbers from 0 to 4 respectively. All remaining elements (represented by 5) will require a lookup table. The resulting table can be pushed as follows: "gØâ^ÃP·^À4Î¾^ß^E5^W^Ma{áª^B¤±´oòæ»^XÊQÑ»4Å¾DÙÝòÙ 0^ÝþKa6^Ó£,Ûkû¥¡ùh^E"256b7b6a/0a3**  The array of character codes gets converted from base 256 to base 7 and 6's are replaced by runs of three 0's. This is the decision table D: [4 0 0 0 1 0 0 0 0 0 0 3 0 2 0 1 0 0 0 0 0 0 0 0 4 1 1 0 0 0 0 2 0 4 0 5 2 0 0 3 4 0 0 0 0 4 0 1 0 0 3 1 0 0 2 1 1 1 0 0 0 1 0 5 5 0 0 2 0 0 0 5 5 0 0 0 5 0 3 0 0 0 0 5 0 0 0 0 0 0 0 0 5 2 3 0 1 0 5 0 4 0 0 0 0 4 0 5 0 0 0 0 0 5 0 0 0 2 5 1 4 1 5 0 0 0 5 0 0 5 1 1 0 0 0 0 0 0 2 0 5 0 0 0 3 1 0 2 0 0 0 2 0 0 0 5 0 0 0 0 1 0 0 0 0 0 4 0 2 2 5 2 0 0 5 1 0 0 0 0 4 0 5 0 0 3 5 0 0 5 0 1 0 0 0 2 0 0 0 0 0 5 0 4 0 0 0 0 0 0 0 0 3 0 4 0 0 1 2 2 0 0 0 0 0]  The necessary action for the element with hash 1, e.g., corresponds to the first element of the this array. Array elements that do not correspond to any element's hash are also zero, which allows the (0 0 0) ↦ 6 compression. Now, we interpret D for hash H. < ) 5 md " Push D[:H-1] (D[H-1] / 5) (D[H-1] % 5). "; @ 5a / , ( " Count the number of 5's in D[:H-1] (by splitting at [5]). Result: I ";  Next, we push the lookup table. If we append j to single-character symbols and replace Uu with Q, each symbol will be exactly two characters long. It can be pushed as follows: " ¬^GH/N¿·%^U^RU1²Bd òë^Ð¼~í^ÌéáU"256b25b'Af+2/  The array of character codes gets converted from base 256 to base 25, the character code of A gets added to all digits (casting to Character in the process) and the result is split into chunks of length two. This is the lookup table L: ["QP" "YB" "PD" "SN" "QO" "QT" "QS" "SB" "KJ" "TM" "FE" "PB" "AU" "WJ" "CN" "SG" "RF" "CM" "CU" "HG" "NA" "RG" "AG"]  Now, we proceed to compute potential element names. = " Push L[I]. "; 'J - 'Q / "UU" * " Remove J's and replace Q's with runs of two U's. "; \ ) _ 5 = ) * " Push S := (D[H-1] % 5 + 1) * ((D[H-1] % 5 + 1 == 5) + 1). "; E % " Push every Sth character of E. "; 2 < " Discard all but the first two characters. ";  The stack now contains B M N  where B is the Boolean D[H-1] / 5, M is the name retrieved from the lookup table an N is the element name formed by selecting characters from E. We're almost done: ? " If B, push M; else, push N. "; ( \ " Extract the first character from the string. "; el " Convert the rest to lowercase. ";  • But how does it work? – Claudiu Oct 7 '14 at 15:25 • @Claudiu: I've added an explanation. – Dennis Oct 8 '14 at 13:49 • I've read the first third of the explanation, and so far what I have is "Magic". Incredible – Mooing Duck Oct 8 '14 at 21:07 • "AcAlAmSbArAsAtBaBkBeBiBhBBrCdCsCaCfCCeClCrCoCnCuCmDsDbDyEsErEuFmFlFFrGdGaGeAuHf HsHeHoHInIIrFeKrLaLrPbLiLvLuMgMnMtMdHgMoNdNeNpNiNbNNoOsOPdPPtPuPoKPrPmPaRaRnReRh RgRbRuRfSmScSgSeSiAgNaSrSTaTcTeTbTlThTmSnTiWUuoUupUusUutUVXeYbYZnZr" = 226 chars. Your solution = 200 chars. There's some proper voodoo going on here. – r3mainer Oct 9 '14 at 15:25 • I've accepted this answer because it appears to be the shortest but feel free to post additional answers. – soktinpk Oct 20 '14 at 21:38 # C, 452 A good hash function helps. There may be better ones. (Improvements suggested by @ugoren et al.) h;main(c){char*p="Sn)Cu&V$U#Mo#Rf#Sg&Cs#Y+FTa%Rb)S'Nd#GaK&Mg'Zr$PtPm%ReUuo#SmDy(Ac$Lu%W&CaRa(Cf)EuB#Ds%Md$Uus*NpIn$H&YbIr*BeEs*Tc#I(FlRuC#ThSrBh/NaCoLrKr&Nb$CePb$Ne'Am)At*PdLa#Tl%HgMt,CrTbBk$Rh&Rn4TeZn$HfAg%Fm)Xe$AlScFePo$As'HeO#LvN&DbGe#Ho&Mn$Cd+Ni$Rg$HsBr$AuSi#Pr&Uup#Se*Ti#Tm$Er$Sb&PPu&Cm$GdBa'Cn&UutLiFr#Ar#Bi#NoOs%Pa4Cl";while((c=getchar())>64)h=(h+c%32+74)*311%441;while(h)if(*p<65?h-=*p++-34,0:1)for(h--;*++p>96;);do putchar(*p++);while(*p>96);}  Ungolfed with comments: int h; main(c) { /* Hashed element symbols. Characters #$% etc. are used as padding: */
char *p="Sn)Cu&V$U#Mo#Rf#Sg&Cs#Y+FTa%Rb)S'Nd#GaK&Mg'Zr$PtPm%ReUuo#SmDy(Ac$Lu%W&C" "aRa(Cf)EuB#Ds%Md$Uus*NpIn$H&YbIr*BeEs*Tc#I(FlRuC#ThSrBh/NaCoLrKr&Nb$CeP"
"b$Ne'Am)At*PdLa#Tl%HgMt,CrTbBk$Rh&Rn4TeZn$HfAg%Fm)Xe$AlScFePo$As'HeO#Lv" "N&DbGe#Ho&Mn$Cd+Ni$Rg$HsBr$AuSi#Pr&Uup#Se*Ti#Tm$Er$Sb&PPu&Cm$GdBa'Cn&Uu"
"tLiFr#Ar#Bi#NoOs%Pa4Cl";

/* This hash function gives a unique result for each element: */
while((c=getchar())>64) h=(h+c%32+74)*311%441;

/* Find the corresponding position in the hashed data */
while(h) {
if(*p<65?h-=*p++-34,0:1) {      /* Step over an abbreviation */
}
}

/* Output first uppercase character and all following lowercase characters: */
do {
putchar(*p++);
} while(*p>96);
}


I used brute force to find this hash; This was the only one with a hash size of ≤512 that had no collisions. I didn't check alternative spellings though, and there might be better functions with different algorithms (e.g. using XOR instead of addition).

The hash function maps text strings to values from 0 to 440. "Tin" hashes to zero, so "Sn" is at the start of the table. The next 7 positions are empty. To keep the code compact, this is indicated by the ASCII value 34+7=41 (")"). Next comes "Copper" (8), four empty cells (34+4=38="&"), and "Vanadium" (13). After calculating a hash, the program steps through the table, subtracting 1 for every capital letter followed by 0 or more lowercase letters, and subtracting (ASCII VALUE)-34 for every non-alphabet character. When the value reaches zero, we have found the correct result.

• @soktinpk Brute forced it :-) This was the only one with a hash size of ≤512 that had no collisions. I didn't check alternative spellings though, and there might be better functions with different algorithms (e.g. using XOR instead of addition). – r3mainer Oct 7 '14 at 1:06
• Make that 464 ... you have an unnecessary pair of braces. – Jim Balter Oct 7 '14 at 5:13
• If you think about the grammar, it's unambiguous and has to be allowed ... it just looks ambiguous to us. Oh, and you caught another one I didn't! Congratulations on this ... I tried hard to tighten the algorithm but you got everything right. – Jim Balter Oct 7 '14 at 8:48
• @Harshdeep — The hash function maps text strings to values from 0 to 440. "Tin" hashes to zero, so "Sn" is at the start of the table. The next 7 positions are empty. To keep the code compact, this is indicated by the ASCII value 34+7=41 (")"). Next comes "Copper" (8), four empty cells (34+4=38="&"), and "Vanadium" (13). After calculating a hash, the program steps through the table, subtracting 1 for every capital letter followed by 0 or more lowercase letters, and subtracting (ASCII VALUE)-34 for every non-alphabet character. When the value reaches zero, we have found the correct result. – r3mainer Oct 7 '14 at 15:17
• Nice one. Save some chars with: 1. (h+c%32+74)*311%441. 2. Drop p and use s. 3. main(c) saves one comma. – ugoren Oct 7 '14 at 21:01

# JavaScript ES6, 690 708 bytes

for(n=prompt()[l='toLowerCase'](i=0);!(c='HHeLiBeBCNFNeNaMgAlSiPSClArKCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsFmMdNoLrRfDbSgBhHsMtDsRgCnUutFlUupLvUusUuo'.match(x=/[A-Z][a-z]*/g)['HyHeLitBeryBorCarNitFluNeonSoMagAlSiliPhSuChlArgPotCalcScTitVChrManIroCobNicCoppZinGalGeArsSelBrKRubStYttrZirNioMoTecRuthenRhoPaSilvCadInTinAnTelIoXCaeBaLanCePraNeodPromSaEuGadTerDyHoErThuYtteLuHafTaTuRheOsIriPlaGoMerThaLeBiPolAsRadoFrRadiAcThoProtUrNepPluAmCuBerkCaliEiFeMenNoLawRutherDuSeaBohHasMeiDaRoCopeUnuntFleUnunpLivUnunsUnuno'.match(x).map(a=>a[l]()).indexOf(n.slice(0,i++))]);)


The first array holds the symbols, and the second array holds the minimum letters necessary to tell which element is being referred to. Thanks to core1024 and edc65 for helping shorten it. Test at http://jsfiddle.net/xjdev4m6/2/. Slightly more readable:

n=prompt().toLowerCase()
s='HHeLiBeBCNFNeNaMgAlSiPSClArKCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsFmMdNoLrRfDbSgBhHsMtDsRgCnUutFlUupLvUusUuo'.match(x)
for(i=0;i<7;i++){
if(c=s[e.indexOf(n.slice(0,i))]){
alert(c,i=8) // i=8 breaks out of the loop so the result is only alerted once
}
}

• Can you shave some bytes off by using the fact that Neo matches Neodymium, given that Neon has been passed in the list? – Dancrumb Oct 7 '14 at 1:28
• @Dancrumb Unfortunately not. The loop starts with the shortest substring, so it will hit Neo before it hits Neon because it has fewer letters. – NinjaBearMonkey Oct 7 '14 at 1:32
• +1 for the shortest JS so far. Although you can get rid of this if statement (It's a perfect for condition) and also to inline or shift the positions of some variables, to shorten the code ;) – core1024 Oct 7 '14 at 18:16
• at beginning ).toLowerCase( --> )[L='toLowerCase']( then at end a.toLowerCase( --> a[L]( should cut 4 chars – edc65 Oct 7 '14 at 22:28

Ruby 1.9+, 565 471 447 444

A one-liner. Because nothing is "impossible to do with regexes"...
(Just saved 94 chars by adding another regex) ((and 24 by simplifying them))

p"VAlAmA.sArAcAnt|SbA.tBaB..kBeBiB.hBrBDyD.+sD.bE..sErEuF..mFrFlu|F@FlG.dGaGeG|AuH.fH.sHeHoHInIro|FeIrIKrL.vL.+rLaLiLuL|PbM.gMoM.+dM.nM.+tM|HgC.+sC.dC.+fCeCar|C@C....nCaCu|CmCop|CuCoC.rC.lN.+dN.+pNeN..bNit|N@NoNiOsOP..mPa|PdP...aPrP.uP..tPot|KPoPR.*n$RaR.+gR.eRhR.+bR.+fRuS.mScS.+gSeS..v|AgSiSo|NaS.rSTaT.cT.+bTeThu|TmT..lThTin|SnTiTu|WU.u.oU.u.pU.u.sU.u.tUXeY.+bYZ.nZ.r" .split(/(?<!\|)(?=[A-Z])/).find{|r|/^#{r}/i.match *$*}.gsub /.*\||\W/,''


usage: ruby periodic.rb aluminum $> Explanation: Splitting the string on leading capitals returns an array of regex to match against element names. The only alphabetic characters allowed in each are those from the abbreviation*. They are ordered such that the first match found when comparing to the command line argument *$* is the correct one. The trailing gsub strips out the non-alpha characters before printing.

*Odd abbreviations like "Fe" for "Iron" are handled by a | element: "Iro|Fe". The first choice is what is actually matched; the gsub then removes all characters up to the '|', leaving the actual abbreviation.

Test framework (requires @squeamish's list: downloaded as 'table.txt' in the working directory).

def testfunc(name)
#replace with however you call your code
return ruby1.9.3 periodic2.rb #{name}.chomp()
end

elements.each{|l|
a,n=l.split(' ')
r = testfunc(n)
print "#{n} => #{a} "
if r!=a then
print ("FAIL: gave #{r}\n")
exit
else
print("\tOK\n")
end
}
print("PASS: #{elements.size} elements matched\n")

• Standing ovation if it works for all 100+ cases – edc65 Oct 8 '14 at 9:09
• Of course it works: ideone.com/7FZlAt – AShelly Oct 8 '14 at 12:42
• One has the audacity to state something can't be done with regex. Thanks for proving them (one said, many thought) wrong :) – Mast Oct 11 '14 at 18:44

## Ruby, 1068 bytes

require"zlib"
require"base64"
$><<eval(Zlib::Inflate.inflate(Base64.decode64"eJwlU8tu2zAQ/Bee+QW6CLYTx0FiR7CdtsmNkmhJCEUKfKQViv57Z9YnE+vd2ZnZ0d+1j2Go6oO2bipzpQ5W6SmPU6nU66S0jatzldqiGmLwVb3VJrZ87NAmoyf9Zx0sKm/alRCnqt5riw514lAvqCejtBm8TZU6Dgp984SGjcMuN3WhUhfsGkNaxqpudHG3Eqv6okdHPLVDXxwIuYmAzCalqn7RxnWkuQN2Z3yPxktH8sbjeQWg8QbV+oceY5iJE1kbDICOHpBE3JNka1zG3wHT3ZeF3hOmw7LYiGpB1XeV+sSIcY4rnwydmQn0hPmYLFduEqpOnhdWg4jcYmlclwyRL3iWdiLTc6s07PNYe0E15wjc+kNPsSOrT9Sm0HLXCZ3BrW0P0iBou9FbyIPSkkfYrs6F1vXsPY9C0aC36entNxVs4LjpZ/EKVX8/ybOnLqzHr8/TzCO0FODgvbreb4dV9bO2npx+oWSTzO6g1ER5bnlZn0eDvIgr9wbqN8kCtIEUG/qVKejFFQvRzYyx2fC6FzxLDAuej4VMg8PzqSeYOHAFrTUtEWAPK80QKQeYwf+B+4gVY5HLXGeaicFKfbS0yGaAvRL35mXsJnwNjnwF3+KHlKv6p4aV4iCIp1lQ3yAyTuLrMxY4k2lXk8kABm8KCXY06wCDR0YDmIiqFf+xfUpzgdYtw+QCc9GAdMqGnDZZtPKAzKLxHYp7JvR+nzNjjZVs7XjhKPpGWpgN8tgYGWNu3rVdcuEnt/DjykRtwG/GOdC5EYfvh5nJWjK+/WJYphts3d2YhZQRrMck0eauPXt9z95jz6/EUuEJEszvyOS9xnsIYcH5xmiLhQ9MkWkDqhcYE0YhvmU0U5ITcMWUGeMjTYgzTqAeUA3W5wFgHMPHhxU7prP4DLD3gmZnY/gGNSflxbIMzROCDnWv31JOUk7yDh3fQf37D7D/kWs="))[gets.downcase[1..5].to_sym]  Input via STDIN. The shortest unique substrings of the element names are from the second to the sixth character (or the end of the name if its too short). So I'm simply getting those and looking them up in a hash. I also compressed the hash because that saves another 200 bytes. Here is what the hash itself looks like: {ydrog:?H,elium:"He",ithiu:"Li",eryll:"Be",oron:?B,arbon:?C,itrog:?N,xygen:?O,luori:?F,eon:"Ne", odium:"Na",agnes:"Mg",lumin:"Al",ilico:"Si",hosph:?P,ulfur:?S,hlori:"Cl",rgon:"Ar",otass:?K, alciu:"Ca",candi:"Sc",itani:"Ti",anadi:?V,hromi:"Cr",angan:"Mn",ron:"Fe",obalt:"Co",ickel:"Ni", opper:"Cu",inc:"Zn",alliu:"Ga",erman:"Ge",rseni:"As",eleni:"Se",romin:"Br",rypto:"Kr",ubidi:"Rb", tront:"Sr",ttriu:?Y,ircon:"Zr",iobiu:"Nb",olybd:"Mo",echne:"Tc",uthen:"Ru",hodiu:"Rh",allad:"Pd", ilver:"Ag",admiu:"Cd",ndium:"In",in:"Sn",ntimo:"Sb",ellur:"Te",odine:?I,enon:"Xe",esium:"Cs", arium:"Ba",antha:"La",erium:"Ce",raseo:"Pr",eodym:"Nd",romet:"Pm",amari:"Sm",uropi:"Eu", adoli:"Gd",erbiu:"Tb",yspro:"Dy",olmiu:"Ho",rbium:"Er",huliu:"Tm",tterb:"Yb",uteti:"Lu", afniu:"Hf",antal:"Ta",ungst:?W,heniu:"Re",smium:"Os",ridiu:"Ir",latin:"Pt",old:"Au",ercur:"Hg", halli:"Tl",ead:"Pb",ismut:"Bi",oloni:"Po",stati:"At",adon:"Rn",ranci:"Fr",adium:"Ra",ctini:"Ac", horiu:"Th",rotac:"Pa",raniu:?U,eptun:"Np",luton:"Pu",meric:"Am",urium:"Cm",erkel:"Bk",alifo:"Cf", inste:"Es",ermiu:"Fm",endel:"Md",obeli:"No",awren:"Lr",uther:"Rf",ubniu:"Db",eabor:"Sg", ohriu:"Bh",assiu:"Hs",eitne:"Mt",armst:"Ds",oentg:"Rg",opern:"Cn",nuntr:"Uut",lerov:"Fl", nunpe:"Uup",iverm:"Lv",nunse:"Uus",nunoc:"Uuo"}  # Python - 652 649 637 My hash table is based on the combination of every second and every third character of the uppercase name: import re def f(s,c='S<8F0FCE;2.ACR;J@W$;BI8>GD*?GnHQ<K>&T\(51IAg/Y?S2=169.,325(F(98?>?=^97DUCITX;SJ0C<P9iLP/G4B,A(-A?(3QLLZ;81D(.4F;L8GaVP[=\=cOX3U,LQl6:E9/OXdSe(4,TSV/=FN98?K.18Q>R$+<GG[IS-4?;4H;T/IMq9<LXMYH4HG<>>KTT,>IIEM,[Nf<,:Z60(A9fImZTMRTcM?[lVg^qC}',e='HHeLiBeBCNOFNeNaMgAlSiPSClArKCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsFmMdNoLrRfDbSgBhHsMtDsRgCnUutFlUupLvUusUuo'): U=s.upper();X=lambda x:chr(32+sum(ord(u)-65for u in x)) return re.findall('[A-Z][a-z]*',e)[zip(c[::2],c[1::2]).index((X(U[1::3]),X(U[:-1:2])))]  Here is the corresponding generator: table = ''' H Hydrogen He Helium ... Uuo Ununoctium ''' table = map(lambda l: l.split(), table.split('\n')[1:-1]) abbr = [] for name in map(str.upper, zip(*table)[1]): abbr.append(chr(32+sum(ord(u)-65 for u in name[1::3]))+ chr(32+sum(ord(u)-65 for u in name[:-1:2]))) print 'c=' + ''.join(abbr) print 'e=' + ''.join(zip(*table)[0]) print 'Unique' if len(table) == len(set(abbr)) else 'Duplicates'  There's probably room for improvements, especially compressing the two long strings. Tested with: for short, name in table: if f(name) != short: print "Wrong result!"  # CJam, 462 449 434 401 391 384 382 With help from Dennis. ## Code Nested ternary ifs are probably not the right way to do this in CJam. rel_"ruthen"#!"Ru"{_"tel"#!"Te"{__5{\_ceu\@=+_}:U~"PdYbRgCmCn"{\#)!}:X~{;__4U"RnPaCfDs"X{;_3U"NbCsNdPmTbPtTlBkEsFmMdLrMt"X{;2U"MgClCrMnZnAsRbSrZrTcCdSmGdHfReAtNpPuDbBhHsLv"X{;__"sili"#{;__ceu\1=@2=++"SodIroCopSilTinAntThuGolMerLeaTunPotRutSeaHydBorCarNitOxyFluPhoSulVanYttIodUra"\#3d/m[)"_NaFeCuAgSnSbTmAuHgPbWKRfSgHBCNOFPSVYIU"S%\=_"_"={;_1U"Un"={;4="Uu"\+}*}*}"Si"?}*}*}*}*}?}?]W=  With indents: rel _"ruthen"#!"Ru" { _"tel"#!"Te" { __5{\_ceu\@=+_}:U~ "PdYbRgCmCn"{\#)!}:X~ { ;__4U "RnPaCfDs"X { ;_3U "NbCsNdPmTbPtTlBkEsFmMdLrMt"X { ;2U "MgClCrMnZnAsRbSrZrTcCdSmGdHfReAtNpPuDbBhHsLv"X { ;__"sili"# { ;__ceu\1=@2=++"SodIroCopSilTinAntThuGolMerLeaTunPotRutSeaHydBorCarNitOxyFluPhoSulVanYttIodUra"\#3d/m[)"_ Na Fe Cu Ag Sn Sb Tm Au Hg Pb W K Rf Sg H B C N O F P S V Y I U"S%\=_"_"= {;_1U"Un"={;4="Uu"\+}*}* } "Si"? }* }* }* }* }? }? ]W=  Many of the symbols are just the first two letters of the element's name. These are handled in the second-deepest layer of nested if statements. Many others are the first and third letter, or the first and fourth letter - these are handled in successive outer layers. Symbols where only the first letter appears, and complete irregulars, are handled in the fifth and third deepest layers respectively. There are a few where it gets confused (TelLurium vs ThaLlium, or SILicon vs SILver, or RUThenium vs RUTherfordium). These are handled separately. A lot of golfing could be done here, mostly by reusing code blocks and improving handling of irregulars. • A few tips: 1. Behavior for invalid element names may be undefined, so rather than "RUTHENIUM"= you can use "RUTHEN"#!. 2. You don't need to print explicitly (o) nor remove anything before the actual element name (;"Si"); just append ]W= to the end of your code to remove everything but the topmost stack element. 3. That makes a few block empty. If B is a Boolean, B{...}{}? and B{...}* achieve the same. 4. The ternary if takes blocks or stack elements, so you can shorten {"Si"} to "Si". – Dennis Oct 8 '14 at 14:03 • @Dennis I think I've added all of that in. The stack management needs work, though - too many _ and ; all over the place – user16402 Oct 8 '14 at 15:09 • @Dennis And I've shaved off a few characters by changing the default case to lowercase and by using the aliased code blocks more – user16402 Oct 8 '14 at 15:21 # PHP, 507485476 466 characters Usage: enter the element name as GET parameter '0' - elements.php?0=carbon Algorithm: Run through the data string, pulling out substring,abbreviation code pairs. If the substring matches the start of the element passed in, use the abbreviation code to determine what to output: If the code starts with a letter, output it as a string. If it is a number N, output the first letter of the element + the Nth letter. The Unun elements are special-cased with the code '|'. If no substring is found that matches the name passed in, output the first two characters of the name as the abbreviation. Readable Code: <?$l=ucfirst(strtolower($_GET[0])); for($m[3]="AnSbArs2As2Berk3Boh2BoBCad2Cae3Cali4CarCChl2Ch2Cope5CopCuCu5Da4Du2Ei3Fe3FluFGad2GoAuHaf2Ha2HyHIo0IroFeLaw3LePbLiv2Mag2Man2Mei3Men3MeHgNeod3Nep2Nio3NiNOxOPa5PhPPla3Plu2PotKProm3Pro4Rado4Rhe2Roe5Rub2Ruther6Sa2Sea6SilvAgSoNaSt2SuSTec2Ter3Tha3Thu6TinSnTuWUn|UUVVYtte5YYZin2Z2";
preg_match('/(.[a-z]*)(.[a-z]*)(.*)/',$m[3],$m)
;)
if(strstr($l,$m[1]))
echo($x=$m[2][0])>'@'?$x>'{'?"Uu$l[4]":$m[2]:$l[0].$l[$x],die;
echo$l[0],$l[1];


Condensed:

<?$l=ucfirst(strtolower($_GET[0]));for($m[3]="AnSbArs2As2Berk3Boh2BoBCad2Cae3Cali4CarCChl2Ch2Cope5CopCuCu5Da4Du2Ei3Fe3FluFGad2GoAuHaf2Ha2HyHIo0IroFeLaw3LePbLiv2Mag2Man2Mei3Men3MeHgNeod3Nep2Nio3NiNOxOPa5PhPPla3Plu2PotKProm3Pro4Rado4Rhe2Roe5Rub2Ruther6Sa2Sea6SilvAgSoNaSt2SuSTec2Ter3Tha3Thu6TinSnTuWUn|UUVVYtte5YYZin2Z2";preg_match('/(.[a-z]*)(.[a-z]*)(.*)/',$m[3],$m);)if(strstr($l,$m[1]))echo($x=$m[2][0])>'@'?$x>'{'?"Uu$l[4]":$m[2]:$l[0].$l[$x],die;echo$l[0],$l[1];  # 05AB1E, 121117112110 109 bytes •S²c¾rƒã∞Øø”.ÑSZl›¹'•2в°T•2nZιć‹ε˜Órv†„₃}Z$+àFQ$•7в1.•®DÝ∍ÌoƵižÒƵaŒ•2ô.;.;6ÝIS¬ì:slƵ{ö•X»²ÄµÕΛεĀδkM•9ävy%}èÙ™  ## JavaScript (1100) Naive implementation shining in its simplicity. Unique sub string from the start of the name is simply mapped to symbol. e={hy:"H",he:"He",lit:"Li",bery:"Be",bor:"B",car:"C",nit:"N",ox:"O",flu:"F",neon:"Ne",so:"Na",mag:"Mg",al:"Al",sili:"Si",ph:"P",su:"S",chl:"Cl",arg:"Ar",pot:"K",calc:"Ca",sc:"Sc",tit:"Ti",v:"V",chr:"Cr",man:"Mn",iro:"Fe",cob:"Co",nic:"Ni",copp:"Cu",zin:"Zn",gal:"Ga",ge:"Ge",ars:"As",sel:"Se",br:"Br",k:"Kr",rub:"Rb",st:"Sr",yttr:"Y",zir:"Zr",nio:"Nb",mo:"Mo",tec:"Tc",ruthen:"Ru",rho:"Rh",pa:"Pd",silv:"Ag",cad:"Cd",in:"In",tin:"Sn",an:"Sb",tel:"Te",io:"I",x:"Xe",cae:"Cs",ba:"Ba",lan:"La",ce:"Ce",pra:"Pr",neod:"Nd",prom:"Pm",sa:"Sm",eu:"Eu",gad:"Gd",ter:"Tb",dy:"Dy",ho:"Ho",er:"Er",thu:"Tm",ytte:"Yb",lu:"Lu",haf:"Hf",ta:"Ta",tu:"W",rhe:"Re",os:"Os",iri:"Ir",pla:"Pt",go:"Au",mer:"Hg",tha:"Tl",le:"Pb",bi:"Bi",pol:"Po",as:"At",rado:"Rn",fr:"Fr",radi:"Ra",ac:"Ac",tho:"Th",prot:"Pa",ur:"U",nep:"Np",plu:"Pu",am:"Am",cu:"Cm",berk:"Bk",cali:"Cf",ei:"Es",fe:"Fm",men:"Md",no:"No",law:"Lr",ruther:"Rf",du:"Db",sea:"Sg",boh:"Bh",has:"Hs",mei:"Mt",da:"Ds",ro:"Rg",cope:"Cn",ununt:"Uut",fle:"Fl",ununp:"Uup",liv:"Lv",ununs:"Uus",ununo:"Uuo"} n=prompt().toLowerCase() for(i in e)n.indexOf(i)?i:alert(e[i])  ## Golfscript - 1052 821 {.91<32*+}%:x;'H He Li Be B C N F Ne Na Mg Al Si P S Cl Ar K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe Cs Ba La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn Fr Ra Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr Rf Db Sg Bh Hs Mt Ds Rg Cn Uut Fl Uup Lv Uus'n/'hy he lit bery bor car nit flu neon so mag al sili ph su chl arg pot calc sc tit v chr man iro cob nic copp zin gal ge ars sel br k rub st yttr zir nio mo tec ruthen rho pa silv cad in tin an tel io x cae ba lan ce pra neod prom sa eu gad ter dy ho er thu ytte lu haf ta tu rhe os iri pla go mer tha le bi pol as rado fr radi ac tho prot ur nep plu am cu berk cali ei fe men no law ruther du sea boh has mei da ro cope ununt fle ununp liv ununs ununo'n/[{x\?)}/]1?=  Explanation: { }% Map these ops to the input string: .91<32*+ Add 32 if less than 91 (convert to lowercase, in essence) :x; Store to x. '...' '...' The first array is the symbols, the second is the names. (stripped down to the minimum necessary) n/ n/ Convert them to arrays. { }/ For each element in the name array... x\?) ...return 1 if the element is found in the input. [ ] Gather every element in an array... 1? Find the 1 in the array (the only element name match)... = ...then return that symbol in the symbol array. (implied) Print.  • OMG, A piece of Golfscript that isn't 10 characters or less! – WallyWest Oct 7 '14 at 5:08 • You can get a massive improvement to that array of strings by using one string with newline as the separator and then doing n/ – Peter Taylor Oct 7 '14 at 8:26 • I did that last time, why the heck didn't I think of that? Updating now. – Josiah Winslow Oct 7 '14 at 20:51 # Haskell, 920817807 776 Chars After working far too long creating a system of rules for what characters of an elements name are included in its symbol, and a bit of tinkering, I managed to write a script that translates element to symbol easily. Iron was a problem for me, because I could sample certain characters from GOld, SilVer, TiN, LEad, SoDium, MerCury, ANtimony, PotaSsium, and TUngsten, converting them to an unused periodic symbol (I chose whichever sampling made it simplest to integrate them into the existing rules), and then translating after symbolic conversion; Iron, however, was a problem, because Ir, Io, and In are all used already. This was initially 920 characters, but I realized that the final pattern match (the largest) didn't need to be there, as it either let things drop through (which it didn't) or matched all of them; therefore, I replaced it with a catch-all wildcard. After that, I further golfed from 817 to 808 by abbreviating some patterns using wild-cards in such a way that they were still unique to that element name (e.g. the only element with a 'w' in its name is Lawrencium, so "*w" matches that in 1 less character than "Law"). Here is my code. I tested it for all of the elements, and I coded it so that it automatically converted its input to titlecase, so no issues with case sensitivity. ## EDIT 1 I further reduced it to 776 characters by replacing the case expression in t with a pattern match (this makes sense because the case expression was testing the raw operand as opposed to an expression in terms of the operand), removing unnecessary parentheses, and re-expressing e as a newline-delimited string instead of a list of strings, and later splitting it in the main function. Because these changes are purely golfing, I have left the human-readable version unchanged. import Data.Char m _[]=True;m[]_=False;m k@(c:s)x@(y:z)=case y of{']'->m s x;'['->let(i,(_:j))=break(==']')z in(celemi)&&m s j;'?'->m s z;'*'->null z||m k z||m s z||m s x;_->c==y&&m s z};p(a:t)(x:y)=case a of{'.'->x:p t y;'_'->p t y;_->a:p t y};p[]_=[];e="Iro\nUn\nCu Pa Ro Y*e\nR*r\n*pp\nCop Rado\nSea Thu\nCali Da P*ot Tha\nA*s Boh ?ub Ch [CG]ad [HM]a Liv Nep Plu Rhe S[ato] Tec Tin Z\nB*k Cae [ES]i *w Nio [FM]e N*d Pro Pla Ter\nBor Car Flu Hy Io Nit Ox Ph Su [UVY]\n*";s="Fe ._._. .____. .f .u .n ._____. .___. ._. .__. . ..";t"Sv"="Ag";t"Sd"="Na";t"Go"="Au";t"Le"="Pb";t"Mc"="Hg";t"An"="Sb";t"Ps"="K";t"Tu"="W";t"Tn"="Sn";t x=x;main=interact$unlines.map(\(a:b)->let y=toUpper a:map toLower b in t$p(snd.head.filter(any(m y).fst)$zip(map words$lines e)$words s)y).lines


import Data.Char

-- Test against search-pattern strings
match _ [] = True
match [] _ = False
match k@(c:s) x@(y:z) = case y of
']' -> match s x
'[' -> let (i,(_:j)) = break (==']') z in (c elem i) && match s j
'?' -> match s z
'*' -> null z || match k z || match s z || match s x
_  -> c == y && match s z

-- Write according to name-pattern string
pattern (a:t) (x:y) = case a of
'.' -> x : (pattern t y)
'_' -> (pattern t y)
_  -> a : (pattern t y)
pattern [] _ = []

-- Search-Patterns for the elements
elements=["Iro", -- Iron -> Fe
"Un", -- UnUn-Blank-ium (1,3,5)
"Cu Pa Ro Y*e", -- CuriuM PallaDium RoentGenium YtterBium (1,6)
"R*r", -- Rutherfordium (1,f)
"*pp", -- Copper (1,u)
"Sea Thu", -- SeaborGium ThuliuM (1,7)
"Cali Da P*ot Tha", -- CaliFornium DarmStadtium ProtActinium PotaSsium (1,5)

{- AsTatine ArSenic BoHrium DuBnium RuBidium ChLorine ChRome CaDmium
GaDolinium HaFnium HaSsium MaNganese MaGnesium LiVermorium NePtunium
PlUtonium RhEnium SaMarium StRontium SoDium TeChnetium TiN ZiNc
ZiRconium (1,3) -}

"A*s Boh ?ub Ch [CG]ad [HM]a Liv Nep Plu Rhe S[ato] Tec Tin Z",

{- BerKelium CaeSium EinSteinum SilIcon SilVer LawRencium NioBium
FerMium MenDelevium MeiTnerium MerCury NeoDymium ProMethium PlaTinum
TerBium (1,4) -}

"B*k Cae [ES]i *w Nio [FM]e N*d Pro Pl Ter",

{- Boron Carbon Fluorine Hydrogen Nitrogen Oxygen Phosphorous Sulphur

"Bor Car Flu Hy Io Nit Ox Ph Su [UVY]",
"*"] -- Everything else (1,2)

-- respective naming patterns for searches
symbol = "Fe ._._. .____. .f .u .n ._____. .___. ._. .__. . .."

-- Translate fake symbols
translate x = case x of
"Sv" -> "Ag" -- SilVer
"Sd" -> "Na" -- SoDium
"Go" -> "Au" -- GOld
"Mc" -> "Hg" -- MerCury
"An" -> "Sb" -- ANtimony
"Ps" -> "K" -- PotaSsium
"Tu" -> "W" -- TUngsten
"Tn" -> "Sn" -- TiN
_  -> x  -- Keep everything else the same

main = interact $unlines . map (\(a:b) -> let y = (toUpper a) : (map toLower b) in t$ p (snd.head.filter (any (m y) . fst) $zip (map words e)$ words s) $y) . lines  If anyone is interested in an explanation for any part of this, feel free to ask. ## C# (826) not the greatest but I thought I'd try it with the handicap of c#. using System;class P{static string s="HyHHe1Li1Be1BoBCaCNitNOxOFlFNe1SoNaMaMgAl1Sil1PhPSuSChClAr1PotKCal1Sc1Tit1VaVChrCrManMnIrFeCo1Ni1CopCuZiZnGa1Ge1ArsAsSe1Br1Kr1RuRbStSrYtYZirZrNioNbMo1TecTcRut1Rh1PaPdSiAgCadCdIn1TiSnAnSbTel1IoIXe1CaeCsBa1La1Ce1Pra1NeoNdPrPmSaSmEu1GadGdTeTbDy1Ho1Er1ThTmYttYbLu1HaHfTa1TuWRheReOs1Iri1PlPtGoAuMeHgThaTlLePbBi1Po1AsAtRaRnFr1Rad1Ac1Tho1ProPaUrUNepNpPluPuAm1CuCmBerBkCaliCfEiEsFeFmMenMdNo1LawLrRuthRfDuDbSeaSgBohBhHasHsMeiMtDaDsRoRgCopeCnUnUutFle1UnuUupLivLvUnunUus",n,t,k;static void Main(){var d=new System.Collections.Specialized.StringDictionary();while(s!=""){k=g;d[k]=g;if(d[k]=="1")d[k]=k.Substring(0,2);};t=Console.ReadLine();while(t!=""&!d.ContainsKey(t))t=t.Remove(t.Length-1);Console.Write(d[t]);}static string g{get{n="";do n+=s[0];while((s=s.Remove(0,1))!=""&&s[0]>96);return n;}}}  So I wrote a program to turn the full name of elements (e.g. carbon) in to the smallest but still unique string possible and did this for all elements with respect to all the other unique strings. I then serialized that in to a big ugly string where capital letters denote the start of "chunks", with chunks alternating between being keys and values. Like KeyValueKey2Value2 etc. This script desterilizes that big string and cuts a character off the end of the inputted string until it finds it in the dictionary made from the big string. (I should add my knowledge of C# isn't amazing and the original submission I made was just using things I knew but I've subsequently had some tricks pointed out to me by others.) • You can golf this further by changing all type definitions to var. You can save a few more by removing braces after single-statement if blocks. If you assign t.Substring(int, int) to a Func<int, int, string> you can save another couple. – Brandon Oct 7 '14 at 14:51 • I made most variable defs "var" but seems I missed one or two, also totally forgot about bracketless ifs, thanks. – miethpo Oct 7 '14 at 14:56 • You can shave a further 5 characters by varing the string[] r and a further 3 by varing the string t = Console...., lastly, you'll save 7 more by changing return new string[] into return new[] at the very end. – Brandon Oct 8 '14 at 12:42 • There are a handful of other minor improvements that you can perform such as moving your if(...) break; logic into the for loop exit conditions. A number of other logic inversions can be applied, such as a do { } while(..) in your extraction method. This is shorter than adding a separate logical operation for the entry case. I have posted an edit to your code that still needs review / acceptance due to my low rep on this site. Got it down to 870 characters. – nicholas Oct 8 '14 at 18:32 • @Nicholas I'm not sure editing someone else's code golf is polite... – miethpo Oct 9 '14 at 9:05 JavaScript (E6) 1433 Here is un upper limit F=n=>'0H0HYDROGEN0He0HELIUM0Li0LITHIUM0Be0BERYLLIUM0B0BORON0C0CARBON0N0NITROGEN0O0OXYGEN0F0FLUORINE0Ne0NEON0Na0SODIUM0Mg0MAGNESIUM0Al0ALUMINIUM0Si0SILICON0P0PHOSPHORUS0S0SULFUR0Cl0CHLORINE0Ar0ARGON0K0POTASSIUM0Ca0CALCIUM0Sc0SCANDIUM0Ti0TITANIUM0V0VANADIUM0Cr0CHROMIUM0Mn0MANGANESE0Fe0IRON0Co0COBALT0Ni0NICKEL0Cu0COPPER0Zn0ZINC0Ga0GALLIUM0Ge0GERMANIUM0As0ARSENIC0Se0SELENIUM0Br0BROMINE0Kr0KRYPTON0Rb0RUBIDIUM0Sr0STRONTIUM0Y0YTTRIUM0Zr0ZIRCONIUM0Nb0NIOBIUM0Mo0MOLYBDENUM0Tc0TECHNETIUM0Ru0RUTHENIUM0Rh0RHODIUM0Pd0PALLADIUM0Ag0SILVER0Cd0CADMIUM0In0INDIUM0Sn0TIN0Sb0ANTIMONY0Te0TELLURIUM0I0IODINE0Xe0XENON0Cs0CAESIUM0Ba0BARIUM0La0LANTHANUM0Ce0CERIUM0Pr0PRASEODYMIUM0Nd0NEODYMIUM0Pm0PROMETHIUM0Sm0SAMARIUM0Eu0EUROPIUM0Gd0GADOLINIUM0Tb0TERBIUM0Dy0DYSPROSIUM0Ho0HOLMIUM0Er0ERBIUM0Tm0THULIUM0Yb0YTTERBIUM0Lu0LUTETIUM0Hf0HAFNIUM0Ta0TANTALUM0W0TUNGSTEN0Re0RHENIUM0Os0OSMIUM0Ir0IRIDIUM0Pt0PLATINUM0Au0GOLD0Hg0MERCURY0Tl0THALLIUM0Pb0LEAD0Bi0BISMUTH0Po0POLONIUM0At0ASTATINE0Rn0RADON0Fr0FRANCIUM0Ra0RADIUM0Ac0ACTINIUM0Th0THORIUM0Pa0PROTACTINIUM0U0URANIUM0Np0NEPTUNIUM0Pu0PLUTONIUM0Am0AMERICIUM0Cm0CURIUM0Bk0BERKELIUM0Cf0CALIFORNIUM0Es0EINSTEINIUM0Fm0FERMIUM0Md0MENDELEVIUM0No0NOBELIUM0Lr0LAWRENCIUM0Rf0RUTHERFORDIUM0Db0DUBNIUM0Sg0SEABORGIUM0Bh0BOHRIUM0Hs0HASSIUM0Mt0MEITNERIUM0Ds0DARMSTADTIUM0Rg0ROENTGENIUM0Cn0COPERNICIUM0Uut0UNUNTRIUM0Fl0FLEROVIUM0Uup0UNUNPENTIUM0Lv0LIVERMORIUM0Uus0UNUNSEPTIUM0Uuo0UNUNOCTIUM' .match(RegExp('([^0]+)0+'+n,'i'))[1]  Test in FireFox/FireBug console F('Rutherfordium')  Output Rf  # SmileBASIC, 176314181204 1128 bytes INPUT E$Hro$="H Hiu$="He
Lhi$="Li Byl$="Be
Bon$="B Cbo$="C
Nro$="N Oge$="O
For$="F Nn$="Ne
Siu$="Na Mne$="Mg
Ami$="Al Sic$="Si
Psp$="P Sfu$="S
Cor$="Cl Aon$="Ar
Pas$="K Cci$="Ca
Snd$="Sc Tan$="Ti
Vad$="V Com$="Cr
Mga$="Mn In$="Fe
Cal$="Co Nke$="Ni
Cpe$="Cu Zc$="Zn
Gli$="Ga Gma$="Ge
Aen$="As Sen$="Se
Bmi$="Br Kpt$="Kr
Rid$="Rb Son$="Sr
Yri$="Y Zco$="Zr
Nbi$="Nb Myb$="Mo
Thn$="Tc Rhe$="Ru
Rdi$="Rh Pla$="Pd
Sve$="Ag Cmi$="Cd
Iiu$="In T$="Sn
Aim$="Sb Tlu$="Te
Iin$="I Xon$="Xe
Csi$="Cs Biu$="Ba
Lth$="La Pse$="Pr
Ndy$="Nd Pme$="Pm
Sar$="Sm Eop$="Eu
Gol$="Gd Tbi$="Tb
Dpr$="Dy Hmi$="Ho
Eiu$="Er Tli$="Tm
Yer$="Yb Let$="Lu
Hni$="Hf Tta$="Ta
Tgs$="W Rni$="Re
Oiu$="Os Idi$="Ir
Pti$="Pt Gd$="Au
Mcu$="Hg Tll$="Tl
Ld$="Pb Bmu$="Bi
Pon$="Po Aat$="At
Ron$="Rn Fnc$="Fr
Riu$="Ra Ain$="Ac
Tri$="Th Pta$="Pa
Uni$="U Ntu$="Np
Pto$="Pu Ari$="Am
Ciu$="Cm Bke$="Bk
Cif$="Cf Est$="Es
Fmi$="Fm Mde$="Md
Nel$="No Lre$="Lr
Dni$="Db Sbo$="Sg
Bri$="Bh Hsi$="Hs
Mtn$="Mt Dms$="Ds
Rnt$="Rg Cer$="Cn
Unt$="Uut Fro$="Fl
Unp$="Uup Ler$="Lv
Uns$="Uus Uno$="Uuo
S$=VAR(E$[0]+MID$(E$,3,2))IF"Cm"==S$*!VAL(".1"+E$[1])THEN S$="Ce IF LEN(E$)>12THEN S$="Rf ?S$


I chose 3 characters which were mostly unique (the 0th, 2nd, and 3rd), which leaves 2 special cases: Cerium/Curium are both "Ciu", and Ruthenium/Rutherfordium are both "Rhe". For Ciu, I check if the second character of the name is "e" or "E", and for "Rhe", I check the length of the name.

VAR(name) returns the variable with that name. Variable names are case insensitive.

# T-SQL, 900 894 676 bytes

SELECT ISNULL((SELECT LEFT(value,3)FROM
STRING_SPLIT('Sb An-As Ars-At Ast-Bk Berk-Bh Boh-B  Bor-Cd Cad-Cs Cae-Cf Cali-C  Car-Cl Chl-Cr Chr-Cn Cope-Cu Copp-Cm Cu-Ds Da-Db Du-Es Ei-Fm Fe-F  Flu-Gd Gad-Au Go-Hf Haf-Hs Has-H  Hy-I  Io-Fe Iro-Lr Law-Pb Le-Lv Liv-Mg Mag-Mn Man-Mt Mei-Md Men-Hg Mer-Nd Neod-Np Nep-Nb Nio-N  Nit-O  Ox-Pd Pa-P  Ph-Pt Pla-Pu Plu-K  Pot-Pm Prom-Pa Prot-Rn Rado-Re Rhe-Rg Ro-Rb Rub-Rf Ruther-Sm Sa-Sg Sea-Ag Silv-Na So-Sr St-S  Su-Tc Tec-Tb Ter-Tl Tha-Tm Thu-Sn Tin-W  Tu-UuoUnuno-UupUnunp-UusUnuns-UutUnunt-U  Ur-V  V-Yb Ytte-Y  Yttr-Zn Zin-Zr Zir'
,'-')m,t WHERE e LIKE SUBSTRING(value,4,9)+'%'),
(SELECT UPPER(LEFT(e,1))+LOWER(SUBSTRING(e,2,1))FROM t))


Returns are for readability only, the second line is one very long string.

STRING_SPLIT is supported in SQL 2016 and higher.

Input is taken via a pre-existing table t with varchar field e, per our IO standards. Output is padded with spaces to 3 characters; the rules were unclear on whether that was ok. If necessary, I can add a TRIM.

The input table is joined with a table generated with a list of all element symbols (padded to 3 characters) with the shortest unique prefix for each element name (X is sufficient for Xenon, but Rutherfordium requires Ruther to distinguish it from Ruthenium).

EDIT 1: Saved 218 characters by removing the 44 entries from the list whose symbol is the first two letters of their name; the ISNULL` function is used to see if the first query fails to return a row, and if so, generates the symbol (properly cased) from the input element name.