Atomlara Moleküller


44

Meydan okuma

Bir giriş kimyasal formülünü (aşağıya bakınız) parçalayabilen ve ilgili atomlarını formda çıkaran bir program yazın element: atom-count.


Giriş

Örnek giriş:

H2O

Girişiniz her zaman en az bir öğe, ancak ondan fazla olmayacak. Programınız, yuvalanmış olabilecek parantez içeren girişleri kabul etmelidir.

Dizelerdeki öğeler her zaman eşleşir [A-Z][a-z]*, yani her zaman büyük harfle başlarlar. Sayılar her zaman tek basamak olacaktır.


Çıktı

Örnek çıktı (yukarıdaki giriş için):

H: 2
O: 1

Çıktınızı isteğe bağlı olarak yeni bir satır takip edebilirsiniz.


Moleküllerin Yıkılması

Bir parantez kümesinin sağındaki sayılar, içindeki her öğeye dağıtılır:

Mg(OH)2

Çıkması gerekir:

Mg: 1
O: 2
H: 2

Aynı prensip münferit atomlar için de geçerlidir:

O2

Çıkması gerekir:

O: 2

Ve ayrıca zincirleme:

Ba(NO2)2

Çıkması gerekir:

Ba: 1
N: 2
O: 4

Örnekler

> Ba(PO3)2
Ba: 1
P: 2
O: 6

> C13H18O2
C: 13
H: 18
O: 2

> K4(ON(SO3)2)2
K: 4
O: 14
N: 2
S: 4

> (CH3)3COOC(CH3)3
C: 8
H: 18
O: 2

> (C2H5)2NH
C: 4
H: 11
N: 1

> Co3(Fe(CN)6)2
Co: 3
Fe: 2
C: 12
N: 12

Girişler bir okla belirtilir (işaretten büyük >) ;

sayı tahtası

Puanınızın tahtada görünmesi için, bu biçimde olması gerekir:

# Language, Score

Veya bonus kazanırsanız:

# Language, Score (Bytes - Bonus%)

Düzenleme: Köşeli parantezler artık sorunun bir parçası değildir. 23 Eylül UTC saatiyle 3:00 öncesinde gönderilen yanıtlar güvenlidir ve bu değişiklikten etkilenmeyecektir.


İzin verilen girdi biçimleri nelerdir?
Oberon

1
@ZachGates Her ikisini de desteklememize izin verilir, ancak köşeli parantezlerin hala yanlış olduğunu unutmayın. Kimyasal formüllerde AFAIK köşeli parantezler sadece belirtilen konsantrasyonda kullanılır. Ör: [HCl] = 0.01 mol L^-1.
orlp

Onlar, ancak tüm yoğun amaçlar için onları gruplandırma için de kullanacağız. @orlp Gerçekten çok önemli bir şey değilse; bu durumda, dirsekleri tamamen sökeceğim.
Zach Gates,

"Örnekler" bölümüne bakın. İstediğiniz belirli bir şey var mı? @Boron Girişleri a ile gösterilir >.
Zach Gates,

1
Sadece bir not, örnekler hala çoklu rakam atom sayısı olan elementlere sahip.
ProgramcıDan

Yanıtlar:


11

CJam, 59 57 bayt

q{:Ci32/")("C#-"[ ] aC~* Ca C+"S/=~}%`La`-S%$e`{~": "@N}/

CJam tercümanında çevrimiçi olarak deneyin .

Nasıl çalışır

q             e# Read all input from STDIN.
{             e# For each character:
  :Ci         e#   Save it in C and cast to integer.
  32/         e#   Divide the code point by 32. This pushes
              e#   2 for uppercase, 3 for lowercase and 1 for non-letters.
  ")("C#      e#   Find the index of C in that string. (-1 if not found.)
  -           e#   Subtract. This pushes 0 for (, 1 for ), 2 for digits,
              e#   3 for uppercase letters and 4 for lowercase letters.

 "[ ] aC~* Ca C+"

 S/           e#   Split it at spaces into ["[" "]" "aC~*" "Ca" "C+"].
 =~           e#   Select and evaluate the corresponding chunk.
              e#     (   : [    : Begin an array.
              e#     )   : ]    : End an array.
              e#     0-9 : aC~* : Wrap the top of the stack into an array
              e#                  and repeat that array eval(C) times.
              e#     A-Z : Ca   : Push "C".
              e#     a-z : C+   : Append C to the string on top of the stack.
}%            e#
`             e# Push a string representation of the resulting array.
              e# For input (Au(CH)2)2, this pushes the string
              e# [[["Au" [["C" "H"] ["C" "H"]]] ["Au" [["C" "H"].["C" "H"]]]]]
La`           e# Push the string [""].
-             e# Remove square brackets and double quotes from the first string.
S%            e# Split the result at runs of spaces.
$e`           e# Sort and perform run-length encoding.
{             e# For each pair [run-length string]:
  ~           e#   Dump both on the stack.
  ": "        e#   Push that string.
  @N          e#   Rotate the run-length on top and push a linefeed.
}/            e#

10

Pyth, 66 65 bayt

VrSc-`v::z"([A-Z][a-z]*)""('\\1',),"",?(\d+)""*\\1,"`(k))8j": "_N

Python cevabımın limanı. Sadece normal parantez kullanarak girişi destekler.


3
+1. Bir saat içinde üç cevap? Güzel.
Zach Gates,

10

Python3, 157 154 bayt

import re
s=re.sub
f=s("[()',]",'',str(eval(s(',?(\d+)',r'*\1,',s('([A-Z][a-z]*)',r'("\1",),',input()))))).split()
for c in set(f):print(c+":",f.count(c))

Sadece normal parantez kullanarak girişi destekler.

evalYukarıdakileri kullanarak golflü çözümü yaratmadan önce , çok zarif bulduğum bu referans çözümünü yarattım:

import re, collections

parts = filter(bool, re.split('([A-Z][a-z]*|\(|\))', input()))
stack = [[]]
for part in parts:
    if part == '(':
        stack.append([])
    elif part == ')':
        stack[-2].append(stack.pop())
    elif part.isdigit():
        stack[-1].append(int(part) * stack[-1].pop())
    else:
        stack[-1].append([part])

count = collections.Counter()
while stack:
    if isinstance(stack[-1], list):
        stack.extend(stack.pop())
    else:
        count[stack.pop()] += 1

for e, i in count.items():
    print("{}: {}".format(e, i))

6

JavaScript ES6, 366 bayt

function f(i){function g(a,b,c){b=b.replace(/[[(]([^[(\])]+?)[\])](\d*)/g,g).replace(/([A-Z][a-z]?)(\d*)/g,function(x,y,z){return y+((z||1)*(c||1))});return(b.search(/[[(]/)<0)?b:g(0,b)}return JSON.stringify(g(0,i).split(/(\d+)/).reduce(function(q,r,s,t){(s%2)&&(q[t[s-1]]=+r+(q[t[s-1]]||0));return q},{})).replace(/["{}]/g,'').replace(/:/g,': ').replace(/,/g,'\n')}

JS Fiddle: https://jsfiddle.net/32tunzkr/1/

Bunun kısaltılacağından eminim ama işe geri dönmem gerekiyor. ;-)


2
Bunun da kısaltılabileceğinden oldukça eminim. ES6'yı kullanmaktan çekindiğiniz için, fonksiyonlar oluşturmak için büyük ok gösterimini kullanarak başlayabilirsiniz. Ve üstü kapalı returnifade. Şimdilik bu yeterli olmalı.
Ismael Miguel

Ayrıca replaceçok kullanırsınız xyz[R='replace'](...), böylece ilk ve abc[R] (...)sonraki her birini kullanarak bazı baytları kaydedebilirsiniz .
DankMemes 23:15

6

SageMath , 156 148 bayt

import re
i=input()
g=re.sub
var(re.findall("[A-Z][a-z]?",i))
print g("(\d+).(\S+)\D*",r"\2: \1\n",`eval(g("(\d+)",r"*\1",g("([A-Z(])",r"+\1",i)))`)

Burada çevrimiçi deneyin (umarım bağlantı işe yarar, çevrimiçi hesaba ihtiyaç duyabilirsiniz)

Not: Çevrimiçi çalışıyorsanız input(), dizeyle değiştirmeniz gerekir (örn. "(CH3)3COOC(CH3)3").

açıklama

Sage, doğru formatta olmaları koşuluyla cebirsel ifadeleri basitleştirmenize izin verir (bkz. Bu bağlantının 'sembolik manipülasyonu ). Eval () içindeki regex'ler temel olarak girdi dizesini doğru formata sokmaya yarar, örneğin:

+(+C+H*3)*3+C+O+O+C+(+C+H*3)*3

eval()daha sonra bunu basitleştirecek: 8*C + 18*H + 2*Ove daha sonra çıktıyı başka bir regex ikamesiyle biçimlendirme meselesi.


5

Python 3, 414 bayt

Umarım sonucun sırası sayılmaz.

import re
t=input().replace("[", '(').replace("]", ')')
d={}
p,q="(\([^\(\)]*\))(\d*)","([A-Z][a-z]*)(\d*)"
for i in re.findall(q,t):t = t.replace(i[0]+i[1],i[0]*(1if i[1]==''else int(i[1])))
r=re.findall(p,t)
while len(r)>0:t=t.replace(r[0][0]+r[0][1],r[0][0][1:-1]*(1if r[0][1]==''else int(r[0][1])));r=re.findall(p,t)
for i in re.findall(q[:-5], t):d[i]=d[i]+1if i in d else 1
for i in d:print(i+': '+str(d[i]))

5

Javascript (ES6), 286 284

Diğer ES6'dan çok daha kısa değil ama elimden gelenin en iyisini yaptım. Not: boş bir dize veya geçersiz girişlerin birçoğunu verirseniz, bu hata olacaktır. Ayrıca, tüm grupların sayısının 1'den fazla (yani hayır CO[OH]) olmasını bekler . Bu herhangi bir meydan okuma kurallarını ihlal ederse, bana bildirin.

a=>(b=[],c={},a.replace(/([A-Z][a-z]*)(?![0-9a-z])/g, "$11").match(/[A-Z][a-z]*|[0-9]+|[\[\(]/g).reverse().map(d=>(d*1==d&&b.push(d*1),d.match(/\(|\[/)&&b.pop(),d.match(/[A-Z]/)&&eval('e=b.reduce((f,g)=>f*g,1),c[d]=c[d]?c[d]+e:e,b.pop()'))),eval('g="";for(x in c)g+=x+`: ${c[x]}\n`'))

Yığın tabanlı bir yaklaşım kullanır. Birincisi, 1numaraya sahip olmayan herhangi bir elemana eklemek için dizeyi önceden işler , yani Co3(Fe(CN)6)2olur Co3(Fe1(C1N1)6)2. Daha sonra ters sırada döngü yapar ve eleman sayısını biriktirir.

a=>(
  // b: stack, c: accumulator
  b=[], c={},

  // adds the 1 to every element that doesn't have a count
  a.replace(/([A-Z][a-z]*)(?![0-9a-z])/g, "$11")

    // gathers a list of all the elements, counts, and grouping chars
    .match(/[A-Z][a-z]*|[0-9]+|[\[\(]/g)

    // loops in reverse order
    .reverse().map(d=>(

       // d*1 is shorthand here for parseInt(d)
       // d*1==d: true only if d is a number
       // if it's a number, add it to the stack
       d * 1 == d && b.push(d * 1),

       // if there's an opening grouping character, pop the last item
       // the item being popped is that group's count which isn't needed anymore
       d.match(/\(|\[/) && b.pop(),

       // if it's an element, update the accumulator
       d.match(/[A-Z]/) && eval('

         // multiplies out the current stack
         e = b.reduce((f, g)=> f * g, 1),

         // if the element exists, add to it, otherwise create an index for it
         c[d] = c[d] ? c[d] + e : e,

         // pops this element's count to get ready for the next element
         b.pop()
       ')
  )),

  // turns the accumulator into an output string and returns the string
  eval('
    g="";

    // loops through each item of the accumulator and adds it to the string
    // for loops in eval always return the last statement in the for loop
    // which in this case evaluates to g
    for(x in c)
      g+=x+`: ${c[x]}\n`
  ')
)

Keman


5

Perl, 177, 172 bayt

171 bayt kodu + 1 bayt komut satırı parametresi

Tamam, bu konuda regex ile biraz taşınmış olabilir ...

s/(?>[A-Z][a-z]?)(?!\d)/$&1/g;while(s/\(([A-Z][a-z]?)(\d+)(?=\w*\W(\d+))/$2.($3*$4).$1/e||s/([A-Z][a-z]?)(\d*)(\w*)\1(\d*)/$1.($2+$4).$3/e||s/\(\)\d+//g){};s/\d+/: $&\n/g

Kullanım örneği:

echo "(CH3)3COOC(CH3)3" | perl -p entry.pl

2

Mathematica, 152 bayt

f=TableForm@Cases[PowerExpand@Log@ToExpression@StringReplace[#,{a:(_?UpperCaseQ~~___?LowerCaseQ):>"\""<>a<>"\"",b__?DigitQ:>"^"<>b}],a_. Log[b_]:>{b,a}]&

Yukarıdaki, bir fdizgeyi girdi olarak alan bir işlevi tanımlar . İşlev dizgiyi alır ve her öğe adını tırnak işaretleri içine alır ve her numaradan önce bir infix üsteleme işleci ekler, ardından dizeyi bir ifade olarak yorumlar:

"YBa2Cu3O7" -> ""Y""Ba"^2"Cu"^3"O"^7" -> "Y" "Ba"^2 "Cu"^3 "O"^7

Sonra bunun logaritmasını alır ve genişletir (matematiğin umrunda, logaritmasını ne alacağı :)):

Log["Y" "Ba"^2 "Cu"^3 "O"^7] -> Log["Y"] + 2 Log["Ba"] + 3 Log["Cu"] + 7 Log["O"]

ve sonra Logbir sayının bir çarpımının tüm oluşumlarını bulur {log-argument, number}ve bunları bir tablo halinde ayrıştırır ve çıktılar. Bazı örnekler:

f@"K4(ON(SO3)2)2"
K   4
N   2
O   14
S   4


f@"(CH3)3COOC(CH3)3"
C   8
H   18
O   2


f@"Co3(Fe(CN)6)2"
C   12
Co  3
Fe  2
N   12

1

Java, 827 bayt

import java.util.*;class C{String[]x=new String[10];public static void main(String[]a){new C(a[0]);}C(String c){I p=new I();int[]d=d(c,p);for(int i=0;i<10;i++)if(x[i]!=null)System.out.println(x[i]+": "+d[i]);}int[]d(String c,I p){int[]f;int i,j;Vector<int[]>s=new Vector();while(p.v<c.length()){char q=c.charAt(p.v);if(q=='(')s.add(d(c,p.i()));if(q==')')break;if(q>='A'&&q<='Z'){f=new int[10];char[]d=new char[]{c.charAt(p.v),0};i=1;if(c.length()-1>p.v){d[1]=c.charAt(p.v+1);if(d[1]>='a'&&d[1]<='z'){i++;p.i();}}String h=new String(d,0,i);i=0;for(String k:x){if(k==null){x[i]=h;break;}if(k.equals(h))break;i++;}f[i]++;s.add(f);}if(q>='0'&&q<='9'){j=c.charAt(p.v)-'0';f=s.get(s.size()-1);for(i=0;i<10;)f[i++]*=j;}p.i();}f=new int[10];for(int[]w:s){j=0;for(int k:w)f[j++]+=k;}return f;}class I{int v=0;I i(){v++;return this;}}}

Git deposu w / ungolfed kaynak (mükemmel parite değil, ungolfed çoklu karakter sayılarını destekler).

Bir süredir Java’ya bir temsilde bulunacağımı düşündüm. Kesinlikle herhangi bir ödül kazanmayacağım :).


1

ES6, 198 bayt

f=s=>(t=s.replace(/(([A-Z][a-z]?)|\(([A-Za-z]+)\))(\d+)/,(a,b,x,y,z)=>(x||y).repeat(z)))!=s?f(t):(m=new Map,s.match(/[A-Z][a-z]?/g).map(x=>m.set(x,-~m.get(x))),[...m].map(([x,y])=>x+": "+y).join`\n`)

\nHazır bir yeni satır karakteri nerede .

Ungolfed:

function f(str) {
    // replace all multiple elements with individual copies
    // then replace all groups with copies working outwards
    while (/([A-Z][a-z]?)(\d+)/.test(str) || /\(([A-Za-z]+)\)(\d+)/.test(str)) {
        str = RegExp.leftContext + RegExp.$1.repeat(RegExp.$2) + RegExp.rightContext;
    }
    // count the number of each element in the expansion
    map = new Map;
    str.match(/[A-Z][a-z]?/g).forEach(function(x) {
        if (!map.has(x)) map.set(x, 1);
        else map.set(x, map.get(x) + 1);
    }
    // convert to string
    res = "";
    map.forEach(function(value, key) {
        res += key + ": " + value + "\n";
    }
    return res;
}

1

Pip , 85 77 + 1 = 78 bayt

Rekabet etmeyen cevap, çünkü zorluktan daha yeni olan dil özelliklerini kullanır. Formülü bir komut satırı argümanı olarak alır ve -nbayrağı uygun çıktı formatlaması için kullanır .

Y(VaRl:`([A-Z][a-z]*)``"&"`R`\d+``X&`R`(?<=\d|")[("]``.&`l)u:UQyu.": ".Y_NyMu

Çevrimiçi deneyin!

Asıl püf noktası, formülü regex değişimleri ile bir Pip ifadesine dönüştürmektir. Bu, değerlendirildiğinde, tekrarlamayı yapacak ve parantezleri bizim için çözecektir. Daha sonra atomun sayımını almak ve her şeyi doğru formatlamak için bir işlem sonrası bit.

Ungolfed, yorumlarla:

                         a is command-line arg (implicit)
l:`([A-Z][a-z]*)`        Regex matching element symbols
aR:l `"&"`               Replace each symbol in a with symbol wrapped in quotes
aR:`\d+` `X&`            Add X before each number
aR:`(?<=\d|")[("]` `.&`  Add . before ( or " if it's preceded by a digit or "
Y (Va)@l                 Eval result, findall matches of l, and yank resulting list into y
u:UQy                    Remove duplicates and store in u
u.": ".(_Ny M u)         Map function {a IN y} to u, returning list of element counts;
                           append this (with colon & space) itemwise to list of symbols
                         Print that list, newline-separated (implicit, -n flag)

Girişin nasıl Co3(Fe(CN)6)2dönüştürüldüğü:

Co3(Fe(CN)6)2
"Co"3("Fe"("C""N")6)2
"Co"X3("Fe"("C""N")X6)X2
"Co"X3.("Fe".("C"."N")X6)X2
CoCoCoFeCNCNCNCNCNCNFeCNCNCNCNCNCN

Sonra:

["Co" "Co" "Co" "Fe" "C" "N" "C" "N" "C" "N" "C" "N" "C" "N" "C" "N" "Fe" "C" "N" "C" "N" "C" "N" "C" "N" "C" "N" "C" "N"]
["Co" "Fe" "C" "N"]
[3 2 12 12]
["Co: 3" "Fe: 2" "C: 12" "N: 12"]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.