public static function parse($value)
    {
        if ($value instanceof Complex) return $value;
        if ($value instanceof Rational) return new Complex($value.p/$value.q, 0);

        if (is_int($value)) return new Complex($value, 0);
        if (is_float($value)) return new Complex($value, 0);

        if (!is_string($value)) throw new SyntaxErrorException();

        // Match complex numbers with an explicit i
        $matches = array();

        $valid = \preg_match(
            '#^([-,\+])?([0-9/,\.]*?)([-,\+]?)([0-9/,\.]*?)i$#',
            \trim($value),
            $matches
        );

        if ($valid == 1) {
            $real = $matches[2];
            if ($real === '') {
                $matches[3] = $matches[1];
                $real = '0';
            }
            $imaginary = $matches[4];
            if ($imaginary === '') $imaginary = '1';

            if ($matches[1] && $matches[1] == '-') {
                $real = '-' . $real;
            }
            if ($matches[3] && $matches[3] == '-') {
                $imaginary = '-' . $imaginary;
            }

            try {
                $a = Rational::parse($real);
                $realPart = $a->p/$a->q;
            } catch(SyntaxErrorException $e)
            {
                $realPart = static::parseReal($real);
            }

            try {
                $b = Rational::parse($imaginary);
                $imaginaryPart = $b->p/$b->q;
            } catch(SyntaxErrorException $e)
            {
                $imaginaryPart = static::parseReal($imaginary);
            }

        }
        else {
            // That failed, try matching a rational number
            try {

                $a = Rational::parse($value);
                $realPart = $a->p/$a->q;
                $imaginaryPart = 0;

            } catch(SyntaxErrorException $e) {
                // Final attempt, try matching a real number
                $realPart = static::parseReal($value);
                $imaginaryPart = 0;
            }
        }

        $z = new Complex($realPart, $imaginaryPart);

        return $z;
    }