Phân tử nguyên tử


44

Các thách thức

Viết chương trình có thể phá vỡ một công thức hóa học đầu vào (xem bên dưới) và xuất ra các nguyên tử tương ứng của nó ở dạng element: atom-count.


Đầu vào

Đầu vào mẫu:

H2O

Đầu vào của bạn sẽ luôn chứa ít nhất một yếu tố, nhưng không quá mười. Chương trình của bạn nên chấp nhận các đầu vào có chứa dấu ngoặc đơn, có thể được lồng vào nhau.

Các thành phần trong chuỗi sẽ luôn khớp [A-Z][a-z]*, có nghĩa là chúng sẽ luôn bắt đầu bằng một chữ cái viết hoa. Các số sẽ luôn là một chữ số.


Đầu ra

Đầu ra mẫu (cho đầu vào trên):

H: 2
O: 1

Đầu ra của bạn có thể được tùy chọn theo sau bởi một dòng mới.


Phân tử phân tử

Các số ở bên phải của một bộ dấu ngoặc đơn được phân phối cho từng phần tử bên trong:

Mg(OH)2

Nên đầu ra:

Mg: 1
O: 2
H: 2

Nguyên tắc tương tự áp dụng cho các nguyên tử riêng lẻ:

O2

Nên đầu ra:

O: 2

Và cũng xâu chuỗi:

Ba(NO2)2

Nên đầu ra:

Ba: 1
N: 2
O: 4

Ví dụ

> 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

Đầu vào được ký hiệu bằng một mũi tên (lớn hơn dấu; >).

Bảng điểm

Để điểm số của bạn xuất hiện trên bảng, nó phải ở định dạng này:

# Language, Score

Hoặc nếu bạn kiếm được tiền thưởng:

# Language, Score (Bytes - Bonus%)

Chỉnh sửa: Dấu ngoặc vuông không còn là một phần của câu hỏi. Bất kỳ câu trả lời nào được đăng trước 3 giờ UTC, ngày 23 tháng 9, đều an toàn và sẽ không bị ảnh hưởng bởi thay đổi này.


Các hình thức đầu vào được phép là gì?
Oberon

1
@ZachGates Tốt hơn là chúng tôi được phép hỗ trợ, nhưng hãy nhớ rằng dấu ngoặc vuông vẫn không chính xác. AFAIK trong công thức hóa học dấu ngoặc vuông chỉ được sử dụng để chỉ định nồng độ. Vd : [HCl] = 0.01 mol L^-1.
orlp

Chúng là, nhưng cho tất cả các mục đích chuyên sâu, chúng tôi cũng sẽ sử dụng chúng để nhóm. @orlp Trừ khi nó thực sự là một vấn đề lớn; trong trường hợp đó, tôi sẽ loại bỏ hoàn toàn dấu ngoặc.
Zach Gates

Xem phần "Ví dụ". Có điều gì cụ thể bạn đang hỏi về? @Oberon Đầu vào được ký hiệu là a >.
Zach Gates

1
Chỉ cần một lưu ý, các ví dụ vẫn có các yếu tố với số lượng nguyên tử nhiều chữ số.
Lập trình viên

Câu trả lời:


11

CJam, 59 57 byte

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

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

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

Bình thường, 66 65 byte

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

Cổng câu trả lời Python của tôi. Chỉ hỗ trợ đầu vào bằng cách sử dụng dấu ngoặc thông thường.


3
+1. Ba câu trả lời trong một giờ? Đẹp.
Zach Gates

10

Python3, 157 154 byte

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

Chỉ hỗ trợ đầu vào bằng cách sử dụng dấu ngoặc thông thường.

Trước khi tạo giải pháp đánh gôn bằng cách sử dụng evalở trên, tôi đã tạo ra giải pháp tham chiếu này, điều mà tôi thấy rất thanh lịch:

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 byte

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')}

Câu đố về JS: https://jsfiddle.net / 32tunzkr / 1 /

Tôi khá chắc chắn rằng điều này có thể được rút ngắn, nhưng tôi cần phải quay lại làm việc. ;-)


2
Tôi khá chắc chắn rằng nó cũng có thể được rút ngắn. Vì bạn bắt đầu sử dụng ES6, bạn có thể bắt đầu bằng cách sử dụng ký hiệu mũi tên lớn để tạo chức năng. Và returntuyên bố ngầm . Điều đó là đủ cho bây giờ.
Ismael Miguel

Bạn cũng sử dụng replacerất nhiều để bạn có thể lưu một số byte bằng cách sử dụng xyz[R='replace'](...)lần đầu tiên và abc[R] (...)mỗi lần tiếp theo.
DankMeme

6

SageMath , 156 148 byte

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

Dùng thử trực tuyến tại đây (hy vọng liên kết sẽ hoạt động, có thể cần một tài khoản trực tuyến)

Lưu ý: Nếu thử trực tuyến, bạn sẽ cần thay thế input()bằng chuỗi (ví dụ "(CH3)3COOC(CH3)3")

Giải trình

Sage cho phép bạn đơn giản hóa các biểu thức đại số, miễn là chúng ở đúng định dạng (xem 'Thao tác biểu tượng' của liên kết này ). Các biểu thức bên trong eval () về cơ bản phục vụ để đưa chuỗi đầu vào vào đúng định dạng, ví dụ như:

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

eval()sau đó sẽ đơn giản hóa điều này thành : 8*C + 18*H + 2*O, và sau đó chỉ là vấn đề định dạng đầu ra với một sự thay thế regex khác.


5

Python 3, 414 byte

Tôi hy vọng rằng thứ tự của kết quả không được tính.

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

Không ngắn hơn nhiều so với ES6 khác nhưng tôi đã cố gắng hết sức. Lưu ý: điều này sẽ báo lỗi nếu bạn cung cấp cho nó một chuỗi rỗng hoặc hầu hết các đầu vào không hợp lệ. Cũng hy vọng tất cả các nhóm sẽ có số lượng nhiều hơn 1 (nghĩa là không CO[OH]). Nếu điều này phá vỡ bất kỳ quy tắc thách thức, cho tôi biết.

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`'))

Sử dụng một cách tiếp cận dựa trên ngăn xếp. Đầu tiên, nó tiền xử lý chuỗi để thêm 1vào bất kỳ phần tử nào mà không có số, tức là Co3(Fe(CN)6)2trở thành Co3(Fe1(C1N1)6)2. Sau đó, nó lặp lại theo thứ tự ngược lại và tích lũy số lượng phần tử.

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`
  ')
)

Vĩ cầm


5

Perl, 177 172 byte

Mã 171 byte + tham số dòng lệnh 1 byte

Ok, vì vậy tôi có thể đã mang đi một chút với regex trên cái này ...

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

Ví dụ sử dụng:

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

2

Toán học, 152 byte

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

Ở trên định nghĩa một hàm flấy một chuỗi làm đầu vào. Hàm lấy chuỗi và bọc từng tên thành phần vào dấu ngoặc kép và thêm toán tử lũy thừa infix trước mỗi số, sau đó diễn giải chuỗi dưới dạng một biểu thức:

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

Sau đó, nó lấy logarit của nó và mở rộng nó ra (mathicala không quan tâm, lấy gì để logarit của :)):

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

và sau đó nó tìm thấy tất cả các lần nhân của Logmột số và phân tích nó thành dạng {log-argument, number}và xuất ra những thứ trong một bảng. Vài ví dụ:

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 byte

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;}}}

Kho lưu trữ Git w / nguồn không được xử lý (không tương đương hoàn hảo, không được hỗ trợ số lượng nhiều ký tự).

Được một lúc, tôi nghĩ rằng tôi sẽ cho Java một số đại diện. Chắc chắn sẽ không giành được bất kỳ giải thưởng nào :).


1

ES6, 198 byte

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

Trường hợp \nlà một nhân vật dòng chữ mới.

Ung dung:

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 byte

Câu trả lời không cạnh tranh vì nó sử dụng các tính năng ngôn ngữ mới hơn thách thức. Lấy công thức làm đối số dòng lệnh và sử dụng -ncờ để định dạng đầu ra thích hợp.

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

Hãy thử trực tuyến!

Thủ thuật chính là chuyển đổi công thức thông qua thay thế regex thành biểu thức Pip. Điều này, khi eval'd, sẽ thực hiện việc lặp lại và giải quyết dấu ngoặc đơn cho chúng ta. Sau đó chúng tôi xử lý hậu kỳ một chút để có được số nguyên tử và định dạng mọi thứ chính xác.

Ungolfed, với ý kiến:

                         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)

Đây là cách đầu vào Co3(Fe(CN)6)2được chuyển đổi:

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

Sau đó:

["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"]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.