diff --git a/chemical-equation.cabal b/chemical-equation.cabal
--- a/chemical-equation.cabal
+++ b/chemical-equation.cabal
@@ -1,6 +1,6 @@
 Cabal-Version:       2.2
 Name:                chemical-equation
-Version:             0.0.1
+Version:             0.0.2
 Synopsis:            Balance chemical equations
 Description:
   Balance coefficients of chemical equations.
@@ -19,6 +19,9 @@
   > $ balance-chemical-equation C8H18 O2 CO2 H2O
   > 2 C8H18 + 25 O2 <=> 16 CO2 + 18 H2O
   .
+  > $ balance-chemical-equation NH4Cl "Ca(OH)2" NH3 CaCl2 H2O
+  > 2 NH4Cl + Ca(OH)2 <=> 2 NH3 + CaCl2 + 2 H2O
+  .
   You may use a custom reaction arrow:
   .
   > $ balance-chemical-equation --arrow="->" HCl NaOH NaCl H2O
@@ -28,6 +31,10 @@
   .
   > $ balance-chemical-equation --unicode --arrow=$'\u21CC' N2 H2 NH3
   .
+  Ion charges in @mhchem@ notation:
+  .
+  > $ balance-chemical-equation --unicode --arrow=$'\u2192' Ca^2+ Cl^- CaCl2
+  .
   If you mix multiple reactions
   then the program takes them apart, again.
   However, the resulting partial reactions may not be chemically sensible.
@@ -69,7 +76,7 @@
   Default: False
 
 Source-Repository this
-  Tag:         0.0.1
+  Tag:         0.0.2
   Type:        darcs
   Location:    https://hub.darcs.net/thielema/chemical-equation
 
diff --git a/src/Common.hs b/src/Common.hs
--- a/src/Common.hs
+++ b/src/Common.hs
@@ -14,9 +14,12 @@
 import Data.Set (Set)
 import Data.Maybe (mapMaybe, isNothing)
 import Data.Tuple.HT (mapPair, mapSnd, swap)
+import Data.Bool.HT (if')
 
+import qualified Text.Parsec.Pos as SourcePos
 import qualified Text.Parsec as Parsec
 import Text.Parsec.String (Parser)
+import Text.Parsec ((<|>))
 
 import Text.Printf (printf)
 
@@ -25,31 +28,70 @@
 import qualified Shell.Utility.Log as Log
 import Shell.Utility.Verbosity (Verbosity)
 
-import Control.Monad (when)
-import Control.Applicative (liftA2, liftA3, (<$>))
+import Control.Monad (when, void)
+import Control.Applicative (liftA2, liftA3, (<$>), (<*))
 
 
 
 type Reactant = Map String Integer
 
 
+consuming :: Parser a -> Parser (String, a)
+consuming p = do
+   input <- Parsec.getInput
+   posBefore <- Parsec.getPosition
+   result <- p
+   posAfter <- Parsec.getPosition
+   return
+      (take (SourcePos.sourceColumn posAfter
+               - SourcePos.sourceColumn posBefore) input,
+       result)
+
+parseElement :: Parser Reactant
+parseElement =
+   flip Map.singleton 1 <$> liftA2 (:) Parsec.upper (Parsec.many Parsec.lower)
+
+parseMultiplicity :: String -> Parser Integer
+parseMultiplicity partStr = do
+   kStr <- Parsec.many Parsec.digit
+   case (kStr, read kStr) of
+      ("", _) -> return 1
+      {- ToDo:
+      should be an unrecoverable parser error
+      in order to not generate confusing additional errors,
+      e.g. when parsing C0
+      -}
+      (_, 0) ->
+         Parsec.unexpected $
+         printf "%s has multiplicity zero" partStr
+      (_, k) -> return k
+
+chargeStr :: String
+chargeStr = "charge"
+
+parseCharge :: Parser Reactant
+parseCharge = do
+   void $ Parsec.char '^'
+   k <- parseMultiplicity chargeStr
+   c <- k <$ Parsec.char '+'  <|>  (-k) <$ Parsec.char '-'
+   return $ Map.singleton chargeStr c
+
+parsePart :: Parser Reactant
+parsePart =
+   fmap (Map.unionsWith (+)) $
+   flip Parsec.sepBy1 (Parsec.optional (Parsec.char '-')) $ do
+      (partStr,part) <-
+         consuming $
+            Parsec.between (Parsec.char '(') (Parsec.char ')') parsePart
+            <|>
+            parseCharge
+            <|>
+            parseElement
+      k <- parseMultiplicity partStr
+      return ((k*) <$> part)
+
 parseReactant :: Parser Reactant
-parseReactant =
-   fmap (Map.fromListWith (+)) $
-   Parsec.many1 $ do
-      element <- liftA2 (:) Parsec.upper (Parsec.many Parsec.lower)
-      kStr <- Parsec.many Parsec.digit
-      case (kStr, read kStr) of
-         ("", _) -> return (element, 1)
-         {- ToDo:
-         should be an unrecoverable parser error
-         in order to not generate confusing additional errors,
-         e.g. when parsing C0
-         -}
-         (_, 0) ->
-            Parsec.unexpected $
-            printf "element %s has multiplicity zero" element
-         (_, k) -> return (element, k)
+parseReactant = parsePart <* Parsec.eof
 
 preprocessArguments ::
    Verbosity -> [String] -> IO (Set Reactant, [(Reactant, String)])
@@ -105,20 +147,29 @@
 
 type Format = [(Reactant,String)] -> Map Reactant Integer -> String
 
+toUnicode :: String -> String
+toUnicode =
+   let go [] = []
+       go (c:cs) =
+         if' (c=='^')
+            (case mapSnd (splitAt 1) $ span Char.isDigit cs of
+               (ds, (sign,remnd)) ->
+                  map Unicode.superscript (ds++sign) ++ go remnd) $
+         if' (Char.isDigit c) (Unicode.subscript c : go cs) $
+         c : go cs
+   in go
+
 formatEquation :: Bool -> String -> Format
 formatEquation useUnicode arrow rs reactantMap =
-   let applyCond b f x = if b then f x else x
-       toSubscript =
-         applyCond useUnicode
-            (map (\c -> applyCond (Char.isDigit c) Unicode.subscript c))
+   let eyeCandy = if useUnicode then toUnicode else id
        tagged =
          mapMaybe
             (\(r,name) ->
                let n = reactantMap Map.! r in
                case compare n 0 of
                   EQ -> Nothing
-                  GT -> Just $ (True,  ( n, toSubscript name))
-                  LT -> Just $ (False, (-n, toSubscript name)))
+                  GT -> Just $ (True,  ( n, eyeCandy name))
+                  LT -> Just $ (False, (-n, eyeCandy name)))
             rs
        (lhs,rhs) =
          (case tagged of ((True,_):_) -> id; _ -> swap) $
