53
\$\begingroup\$

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!

\$\endgroup\$
11
  • 5
    \$\begingroup\$ @squeamishossifrage Thanks. Both versions ("sulphur" and "sulfur") are acceptable. Your program does not have to handle both, however, only one. \$\endgroup\$
    – soktinpk
    Oct 6, 2014 at 20:58
  • 1
    \$\begingroup\$ ...impossible to do with regexes. You got us good. \$\endgroup\$ Oct 6, 2014 at 22:30
  • 3
    \$\begingroup\$ @Xrylite Try reading the rules: "Input ... the element name - case insensitive ... Output ... The first character must be capitalized and the rest must be lowercase". \$\endgroup\$
    – Jim Balter
    Oct 7, 2014 at 5:30
  • 2
    \$\begingroup\$ What about proper spelling (Aluminium) versus US spelling (Aluminum) ? \$\endgroup\$
    – Paul R
    Oct 7, 2014 at 9:40
  • 6
    \$\begingroup\$ @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. \$\endgroup\$
    – soktinpk
    Oct 7, 2014 at 21:21

18 Answers 18

44
\$\begingroup\$

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 */
      for(h--;*++p>96;);            /* Skip padding */
    }
  }
  
  /* 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.

\$\endgroup\$
18
  • 3
    \$\begingroup\$ @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). \$\endgroup\$
    – r3mainer
    Oct 7, 2014 at 1:06
  • 2
    \$\begingroup\$ Make that 464 ... you have an unnecessary pair of braces. \$\endgroup\$
    – Jim Balter
    Oct 7, 2014 at 5:13
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Jim Balter
    Oct 7, 2014 at 8:48
  • 5
    \$\begingroup\$ @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. \$\endgroup\$
    – r3mainer
    Oct 7, 2014 at 15:17
  • 2
    \$\begingroup\$ 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. \$\endgroup\$
    – ugoren
    Oct 7, 2014 at 21:01
30
\$\begingroup\$

CJam, 337 297 293 232 220 201 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
"' NwEvKv6e8@]jO4G)=b{L!v@hFQ/oCN)*|BRxvNRL+LO7NI(pLs4[d87$Q%8R\t+' M5JU"
{32f-95b}:B~7b6a/0a3**<)5md@5a/,(
"&y.$h*z^t\rQPUc]l8F h$=18C^r|vD~S"
B25b'Af+2/='J-'Q/"UU"*\)_5=)*E%2<?(\el

You can try this code in the CJam interpreter.

Test cases

$ base64 -d > elements.cjam <<< bGV1OkUyZl4zYjIrNCVfIjUzTjU5MDNDVkNUNCI6aTMvPX5FZitiXCVdNTNiImfY4oNQt4A0zr6fBTUXDWF74aoCpLG0b/LmuxjKUdG7NMW+RNnd8tmgMJ3+S2E2k6Ms22v7paH5aAUiMjU2YjdiNmEvMGEzKio8KTVtZEA1YS8sKCIgrAdIL06/tyUVElUxskJkCvLrkLx+7Yzp4VUiMjU2YjI1YidBZisyLz0nSi0nUS8iVVUiKlwpXzU9KSpFJTI8PyhcZWw=
$ 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.                                         ";
\$\endgroup\$
7
  • \$\begingroup\$ But how does it work? \$\endgroup\$
    – Claudiu
    Oct 7, 2014 at 15:25
  • 2
    \$\begingroup\$ @Claudiu: I've added an explanation. \$\endgroup\$
    – Dennis
    Oct 8, 2014 at 13:49
  • 4
    \$\begingroup\$ I've read the first third of the explanation, and so far what I have is "Magic". Incredible \$\endgroup\$ Oct 8, 2014 at 21:07
  • 9
    \$\begingroup\$ "AcAlAmSbArAsAtBaBkBeBiBhBBrCdCsCaCfCCeClCrCoCnCuCmDsDbDyEsErEuFmFlFFrGdGaGeAuHf HsHeHoHInIIrFeKrLaLrPbLiLvLuMgMnMtMdHgMoNdNeNpNiNbNNoOsOPdPPtPuPoKPrPmPaRaRnReRh RgRbRuRfSmScSgSeSiAgNaSrSTaTcTeTbTlThTmSnTiWUuoUupUusUutUVXeYbYZnZr" = 226 chars. Your solution = 200 chars. There's some proper voodoo going on here. \$\endgroup\$
    – r3mainer
    Oct 9, 2014 at 15:25
  • \$\begingroup\$ I've accepted this answer because it appears to be the shortest but feel free to post additional answers. \$\endgroup\$
    – soktinpk
    Oct 20, 2014 at 21:38
13
\$\begingroup\$

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++))]);)
alert(c)

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()
e='HyHeLitBeryBorCarNitFluNeonSoMagAlSiliPhSuChlArgPotCalcScTitVChrManIroCobNicCoppZinGalGeArsSelBrKRubStYttrZirNioMoTecRuthenRhoPaSilvCadInTinAnTelIoXCaeBaLanCePraNeodPromSaEuGadTerDyHoErThuYtteLuHafTaTuRheOsIriPlaGoMerThaLeBiPolAsRadoFrRadiAcThoProtUrNepPluAmCuBerkCaliEiFeMenNoLawRutherDuSeaBohHasMeiDaRoCopeUnuntFleUnunpLivUnunsUnuno'.match(x=/[A-Z][a-z]*/g).map(a=>a.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
  }
}
\$\endgroup\$
4
  • \$\begingroup\$ Can you shave some bytes off by using the fact that Neo matches Neodymium, given that Neon has been passed in the list? \$\endgroup\$
    – Dancrumb
    Oct 7, 2014 at 1:28
  • 1
    \$\begingroup\$ @Dancrumb Unfortunately not. The loop starts with the shortest substring, so it will hit Neo before it hits Neon because it has fewer letters. \$\endgroup\$ Oct 7, 2014 at 1:32
  • 1
    \$\begingroup\$ +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 ;) \$\endgroup\$
    – core1024
    Oct 7, 2014 at 18:16
  • 2
    \$\begingroup\$ at beginning ).toLowerCase( --> )[L='toLowerCase']( then at end a.toLowerCase( --> a[L]( should cut 4 chars \$\endgroup\$
    – edc65
    Oct 7, 2014 at 22:28
10
\$\begingroup\$

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|[email protected]|AuH.fH.sHeHoHInIro|FeIrIKrL.vL.+rLaLiLuL|PbM.gMoM.+dM.nM.+tM|HgC.+sC.dC.+fCeCar|[email protected]|CmCop|CuCoC.rC.lN.+dN.+pNeN..bNit|[email protected]|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/,''

(newline after string added for "readability", remove for test)

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= File.new('table.txt').readlines.map{|s|s.chomp}

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")
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Standing ovation if it works for all 100+ cases \$\endgroup\$
    – edc65
    Oct 8, 2014 at 9:09
  • \$\begingroup\$ Of course it works: ideone.com/7FZlAt \$\endgroup\$
    – AShelly
    Oct 8, 2014 at 12:42
  • \$\begingroup\$ One has the audacity to state something can't be done with regex. Thanks for proving them (one said, many thought) wrong :) \$\endgroup\$
    – Mast
    Oct 11, 2014 at 18:44
4
\$\begingroup\$

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"}
\$\endgroup\$
0
4
\$\begingroup\$

JavaScript (Node.js), 298 bytes

s=>(i=`23>3c9@94=4E33:3Q0I3:9[020G0O3@74M9=4A6@4;7J5H96?9K0L723E4343A4R40A0T9D3J5H4?4?3J329>9P9;359:0B9^3=95h6:9<6M0~D0@0N3<3;0:9@4<4<6H3I3`.replace(/\D/g,s=>"2".repeat(Buffer(s)[0]-56))[h=parseInt(s,36)*184%901])-9?s[0]+[s[i-1]]:`Ag,Fe,Hg,,W,Sn,K,Cu,Pb,,Sb,Au,,Na`.split`,`[h%418%48%15]||'Uu'+s[4]

Try it online!

How?

Element groups

We split the elements into 3 groups:

  • Group 1: 12 elements whose symbol is the first letter of their name, such as Carbon -> C.

  • Group 2: 91 elements whose symbol is the first letter of their name, followed by the \$n\$-th letter (0-indexed) with \$1\le n \le6\$. Examples: Helium -> He (\$n=1\$), Zirconium -> Zr (\$n=2\$).

  • Group 3: 15 elements that do not belong to the other groups, such as Iron -> Fe.

This means that all elements can be encoded with a single digit: we use \$0\$ for group 1, \$n+1\$ for group 2 and \$9\$ for group 3. (Obviously, we'll need some extra data for group 3. More on that later.)

It is worth noting that 44 symbols simply consist of the first two letters of the element name. That's almost 50% of group 2. These ones will be encoded with a "2", so that's the padding character that we want to use in our lookup string.

Hash function, lookup string and compression

We apply the following hash function (found by brute-force) on the input string:

h = parseInt(s, 36) * 184 % 901

The corresponding lookup string is \$899\$ characters long, which is pretty big.

But, by design, we have many runs of consecutive \$2\$'s in there. Our compression strategy is to replace each run of \$2\$'s of length \$2\le n\le70\$ with the character whose ASCII code is \$n+56\$ (that's the range going from ":" to "~").

The compressed string is only \$132\$ characters long.

You can see the decompression process here:

Try it online!

Decoding

Groups 1 and 2 are decoded the same way:

s[0] + [s[i - 1]]

(NB: For group 1, s[-1] is undefined and [undefined] is coerced to an empty string.)

For group 3, we use another hash function and another lookup string (also found by brute-force):

`Ag,Fe,Hg,,W,Sn,K,Cu,Pb,,Sb,Au,,Na`.split`,`[h % 418 % 48 % 15]

There are 4 remaining superheavy elements that are not included above. Because they are referred to by their temporary names and thanks to the systematic nomenclature, we can build the symbols for these ones by concatenating "Uu" with the fifth letter of their name:

    v
Ununtrium   -> Uut
Ununpentium -> Uup
Ununseptium -> Uus
Ununoctium  -> Uuo
    ^

Hence the last part of the code:

|| 'Uu' + s[4]
\$\endgroup\$
3
\$\begingroup\$

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;SJ`0C<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!"
\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 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". \$\endgroup\$
    – Dennis
    Oct 8, 2014 at 14:03
  • \$\begingroup\$ @Dennis I think I've added all of that in. The stack management needs work, though - too many _ and ; all over the place \$\endgroup\$
    – user16402
    Oct 8, 2014 at 15:09
  • \$\begingroup\$ @Dennis And I've shaved off a few characters by changing the default case to lowercase and by using the aliased code blocks more \$\endgroup\$
    – user16402
    Oct 8, 2014 at 15:21
3
\$\begingroup\$

PHP, 507 485 476 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];
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 121 117 112 110 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%}èÙ™

Try it online! or validate all test cases.

\$\endgroup\$
2
\$\begingroup\$

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])
\$\endgroup\$
2
\$\begingroup\$

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.
\$\endgroup\$
3
  • 12
    \$\begingroup\$ OMG, A piece of Golfscript that isn't 10 characters or less! \$\endgroup\$ Oct 7, 2014 at 5:08
  • 2
    \$\begingroup\$ You can get a massive improvement to that array of strings by using one string with newline as the separator and then doing n/ \$\endgroup\$ Oct 7, 2014 at 8:26
  • \$\begingroup\$ I did that last time, why the heck didn't I think of that? Updating now. \$\endgroup\$ Oct 7, 2014 at 20:51
2
\$\begingroup\$

Haskell, 920 817 807 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(c`elem`i)&&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

Human-Readable Version (newlines, spacing, verbose names, comments: 2311 Chars)

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)
      "Cop Rado", -- Copernicium Radon (1,n)
      "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
      Uranium Vanadium Yttrium (1) -}

      "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
"Le" -> "Pb" -- LEad
"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.

\$\endgroup\$
2
\$\begingroup\$

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.)

\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$
    – Brandon
    Oct 7, 2014 at 14:51
  • \$\begingroup\$ I made most variable defs "var" but seems I missed one or two, also totally forgot about bracketless ifs, thanks. \$\endgroup\$
    – miethpo
    Oct 7, 2014 at 14:56
  • \$\begingroup\$ 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. \$\endgroup\$
    – Brandon
    Oct 8, 2014 at 12:42
  • \$\begingroup\$ 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. \$\endgroup\$
    – nicholas
    Oct 8, 2014 at 18:32
  • 1
    \$\begingroup\$ @Nicholas I'm not sure editing someone else's code golf is polite... \$\endgroup\$
    – miethpo
    Oct 9, 2014 at 9:05
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

SmileBASIC, 1763 1418 1204 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.

\$\endgroup\$
1
\$\begingroup\$

Retina, 291 286 276 bytes

.*
$u
Pot
K
op
u
Iro
Fe
Silv
Ag
Tin
Sn
0L`.*f|[RS].*g|[CGP]a.*d|(As|Ch|G|Law|Ma|Me.|Pla?|Prot?|Rado|St|Tha|Unun|Zi).|Flu|N[ei]o?[bdpt]|[ACEH].*s|[BDLRST].[bcehmv]|..+r[bkmn]s?|[CT]h?u.*m|..
\B.*\B

T`l``[FHKNOSVY][at-y]|Cb|Bo|Io|Ph|Ur
So
Na
An
Sb
Tu
W
Go
Au
Mc
Hg
Le
Pb
U.
U$l

Try it online!

Verification script (Python)

Explanation

.*
$u

Convert the first letter of the input to uppercase and the rest to lowercase.

0L`.*f|[RS].*g|[CGP]a.*d|(As|Ch|G|Law|Ma|Me.|Pla?|Prot?|Rado|St|Tha|Unun|Zi).|Flu|N[ei]o?[bdpt]|[ACEH].*s|[BDLRST].[bcehmv]|..+r[bkmn]s?|[CT]h?u.*m|..

Truncate each element name, ending with the intended second letter. The default case .. matches the first two letters of the element name.

\B.*\B

Keep only the first and last letter.

T`l``[FHKNOSVY][at-y]|Cb|Bo|Io|Ph|Ur

Remove the lowercase letters from the single-letter abbreviations.

U.
U$l

Insert the u for the elements that require it.


The rest of the program deals with various special-case replacements. Some of these occur before the main regex because those elements share their first two letters with another.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$

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.