fork download
  1. #!/bin/env python3
  2.  
  3. import re
  4.  
  5.  
  6. class Molecule(object):
  7. SPLIT_RE = re.compile(
  8. '(?P<element>[A-Z][a-z]?)(?P<count>\d*)|'
  9. '(?P<open>\()|'
  10. '\)(?P<close>\d+)|'
  11. '.'
  12. )
  13.  
  14. def __init__(self, *, elements):
  15. self._elements = elements
  16.  
  17. @classmethod
  18. def from_string(cls, s):
  19. molecule, remainder = cls.from_tokens(
  20. list(cls.SPLIT_RE.finditer(s))
  21. )
  22. if remainder is not None:
  23. raise ValueError
  24. return molecule
  25.  
  26. @classmethod
  27. def from_tokens(cls, tokens):
  28. molecule = cls(elements=dict())
  29. while tokens:
  30. for ind, t in enumerate(tokens):
  31. if t.group('element'):
  32. molecule += cls.from_token(t)
  33. elif t.group('open'):
  34. next_, remainder = cls.from_tokens(tokens[ind+1:])
  35. next_count = int(remainder[0].group('close'))
  36. next_ *= next_count
  37. molecule += next_
  38. tokens = remainder[1:]
  39. break
  40. elif t.group('close'):
  41. return molecule, tokens[ind:]
  42. else:
  43. raise ValueError
  44. else:
  45. tokens = False
  46. return molecule, None
  47.  
  48. @classmethod
  49. def from_token(cls, token):
  50. return cls(
  51. elements={
  52. token.group('element'): int('0'+token.group('count')) or 1
  53. }
  54. )
  55.  
  56. def __mul__(self, other):
  57. if isinstance(other, int):
  58. return Molecule(
  59. elements={
  60. ele: count * other
  61. for ele, count in self._elements.items()
  62. }
  63. )
  64. else:
  65. raise TypeError
  66.  
  67. def __add__(self, other):
  68. if isinstance(other, Molecule):
  69. elements = self._elements.copy()
  70. for ele, count in other._elements.items():
  71. elements[ele] = elements.get(ele, 0) + count
  72. return Molecule(
  73. elements=elements
  74. )
  75. elif other is None:
  76. return self
  77. else:
  78. raise TypeError
  79.  
  80. def __str__(self):
  81. return '\n'.join(
  82. '{k} -> {v}'.format(k=k, v=v)
  83. for k, v in self._elements.items()
  84. )
  85.  
  86.  
  87. def main():
  88. import sys
  89. for line in sys.stdin:
  90. m = Molecule.from_string(line)
  91. print(m)
  92.  
  93.  
  94. if __name__ == '__main__':
  95. main()
Success #stdin #stdout 0.03s 28352KB
stdin
C6H12O6
CCl2F2
NaHCO3
C4H8(OH)2
PbCl(NH3)2(COOH)2
stdout
O -> 6
H -> 12
C -> 6
F -> 2
C -> 1
Cl -> 2
Na -> 1
O -> 3
H -> 1
C -> 1
O -> 2
H -> 10
C -> 4
N -> 2
H -> 8
O -> 4
Pb -> 1
Cl -> 1
C -> 2