def parse(passed_unit_string = '0')
      unit_string = passed_unit_string.dup
      unit_string = "#{Regexp.last_match(1)} USD" if unit_string =~ /\$\s*(#{NUMBER_REGEX})/
      unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8

      unit_string.gsub!(/[%'"#]/, '%' => 'percent', "'" => 'feet', '"' => 'inch', '#' => 'pound')

      if defined?(Complex) && unit_string =~ COMPLEX_NUMBER
        real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0]
        result                  = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f)
        copy(result)
        return
      end

      if defined?(Rational) && unit_string =~ RATIONAL_NUMBER
        sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0]
        sign = sign == '-' ? -1 : 1
        rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i))
        result = RubyUnits::Unit.new(unit_s || '1') * rational
        copy(result)
        return
      end

      unit_string =~ NUMBER_REGEX
      unit = @@cached_units[Regexp.last_match(2)]
      mult = begin
               (Regexp.last_match(1).empty? ? 1.0 : Regexp.last_match(1).to_f)
             rescue
               1.0
             end
      mult = mult.to_int if mult.to_int == mult
      if unit
        copy(unit)
        @scalar      *= mult
        @base_scalar *= mult
        return self
      end

      while unit_string.gsub!(/(<#{@@unit_regex})><(#{@@unit_regex}>)/, '\1*\2')
        # collapse <x><y><z> into <x*y*z>...
      end
      # ... and then strip the remaining brackets for x*y*z
      unit_string.gsub!(/[<>]/, '')

      if unit_string =~ /:/
        hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0]
        raise ArgumentError, 'Invalid Duration' if [hours, minutes, seconds, microseconds].all?(&:nil?)
        result = RubyUnits::Unit.new("#{hours || 0} h") +
                 RubyUnits::Unit.new("#{minutes || 0} minutes") +
                 RubyUnits::Unit.new("#{seconds || 0} seconds") +
                 RubyUnits::Unit.new("#{microseconds || 0} usec")
        copy(result)
        return
      end

      # Special processing for unusual unit strings
      # feet -- 6'5"
      feet, inches = unit_string.scan(FEET_INCH_REGEX)[0]
      if feet && inches
        result = RubyUnits::Unit.new("#{feet} ft") + RubyUnits::Unit.new("#{inches} inches")
        copy(result)
        return
      end

      # weight -- 8 lbs 12 oz
      pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0]
      if pounds && oz
        result = RubyUnits::Unit.new("#{pounds} lbs") + RubyUnits::Unit.new("#{oz} oz")
        copy(result)
        return
      end

      # stone -- 3 stone 5, 2 stone, 14 stone 3 pounds, etc.
      stone, pounds = unit_string.scan(STONE_LB_REGEX)[0]
      if stone && pounds
        result = RubyUnits::Unit.new("#{stone} stone") + RubyUnits::Unit.new("#{pounds} lbs")
        copy(result)
        return
      end

      # more than one per.  I.e., "1 m/s/s"
      raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1
      raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string =~ /\s[02-9]/
      @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] # parse the string into parts
      top.scan(TOP_REGEX).each do |item|
        n = item[1].to_i
        x = "#{item[0]} "
        if n >= 0
          top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { x * n }
        elsif n < 0
          bottom = "#{bottom} #{x * -n}"
          top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, '')
        end
      end
      if bottom
        bottom.gsub!(BOTTOM_REGEX) { "#{Regexp.last_match(1)} " * Regexp.last_match(2).to_i }
        # Separate leading decimal from denominator, if any
        bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0]
      end

      @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty?
      @scalar = 1 unless @scalar.is_a? Numeric
      @scalar = @scalar.to_int if @scalar.to_int == @scalar

      bottom_scalar = 1 if bottom_scalar.nil? || bottom_scalar.empty?
      bottom_scalar = if bottom_scalar.to_i == bottom_scalar
                        bottom_scalar.to_i
                      else
                        bottom_scalar.to_f
                      end

      @scalar /= bottom_scalar

      @numerator   ||= UNITY_ARRAY
      @denominator ||= UNITY_ARRAY
      @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if top
      @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if bottom

      # eliminate all known terms from this string.  This is a quick check to see if the passed unit
      # contains terms that are not defined.
      used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(%r{[\d\*, "'_^\/\$]}, '')
      raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty?

      @numerator = @numerator.map do |item|
        @@prefix_map[item[0]] ? [@@prefix_map[item[0]], @@unit_map[item[1]]] : [@@unit_map[item[1]]]
      end.flatten.compact.delete_if(&:empty?)

      @denominator = @denominator.map do |item|
        @@prefix_map[item[0]] ? [@@prefix_map[item[0]], @@unit_map[item[1]]] : [@@unit_map[item[1]]]
      end.flatten.compact.delete_if(&:empty?)

      @numerator = UNITY_ARRAY if @numerator.empty?
      @denominator = UNITY_ARRAY if @denominator.empty?
      self
    end
def parse(passed_unit_string = '0')
      unit_string = passed_unit_string.dup
      unit_string = "#{Regexp.last_match(1)} USD" if unit_string =~ /\$\s*(#{NUMBER_REGEX})/
      unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8

      unit_string.gsub!(/[%'"#]/, '%' => 'percent', "'" => 'feet', '"' => 'inch', '#' => 'pound')

      if defined?(Complex) && unit_string =~ COMPLEX_NUMBER
        real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0]
        result                  = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f)
        copy(result)
        return
      end

      if defined?(Rational) && unit_string =~ RATIONAL_NUMBER
        sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0]
        sign = sign == '-' ? -1 : 1
        rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i))
        result = RubyUnits::Unit.new(unit_s || '1') * rational
        copy(result)
        return
      end

      unit_string =~ NUMBER_REGEX
      unit = @@cached_units[Regexp.last_match(2)]
      mult = begin
               (Regexp.last_match(1).empty? ? 1.0 : Regexp.last_match(1).to_f)
             rescue
               1.0
             end
      mult = mult.to_int if mult.to_int == mult
      if unit
        copy(unit)
        @scalar      *= mult
        @base_scalar *= mult
        return self
      end

      while unit_string.gsub!(/(<#{@@unit_regex})><(#{@@unit_regex}>)/, '\1*\2')
        # collapse <x><y><z> into <x*y*z>...
      end
      # ... and then strip the remaining brackets for x*y*z
      unit_string.gsub!(/[<>]/, '')

      if unit_string =~ /:/
        hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0]
        raise ArgumentError, 'Invalid Duration' if [hours, minutes, seconds, microseconds].all?(&:nil?)
        result = RubyUnits::Unit.new("#{hours || 0} h") +
                 RubyUnits::Unit.new("#{minutes || 0} minutes") +
                 RubyUnits::Unit.new("#{seconds || 0} seconds") +
                 RubyUnits::Unit.new("#{microseconds || 0} usec")
        copy(result)
        return
      end

      # Special processing for unusual unit strings
      # feet -- 6'5"
      feet, inches = unit_string.scan(FEET_INCH_REGEX)[0]
      if feet && inches
        result = RubyUnits::Unit.new("#{feet} ft") + RubyUnits::Unit.new("#{inches} inches")
        copy(result)
        return
      end

      # weight -- 8 lbs 12 oz
      pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0]
      if pounds && oz
        result = RubyUnits::Unit.new("#{pounds} lbs") + RubyUnits::Unit.new("#{oz} oz")
        copy(result)
        return
      end

      # stone -- 3 stone 5, 2 stone, 14 stone 3 pounds, etc.
      stone, pounds = unit_string.scan(STONE_LB_REGEX)[0]
      if stone && pounds
        result = RubyUnits::Unit.new("#{stone} stone") + RubyUnits::Unit.new("#{pounds} lbs")
        copy(result)
        return
      end

      # more than one per.  I.e., "1 m/s/s"
      raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1
      raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string =~ /\s[02-9]/
      @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] # parse the string into parts
      top.scan(TOP_REGEX).each do |item|
        n = item[1].to_i
        x = "#{item[0]} "
        if n >= 0
          top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { x * n }
        elsif n < 0
          bottom = "#{bottom} #{x * -n}"
          top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, '')
        end
      end
      if bottom
        bottom.gsub!(BOTTOM_REGEX) { "#{Regexp.last_match(1)} " * Regexp.last_match(2).to_i }
        # Separate leading decimal from denominator, if any
        bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0]
      end

      @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty?
      @scalar = 1 unless @scalar.is_a? Numeric
      @scalar = @scalar.to_int if @scalar.to_int == @scalar

      bottom_scalar = 1 if bottom_scalar.nil? || bottom_scalar.empty?
      bottom_scalar = if bottom_scalar.to_i == bottom_scalar
                        bottom_scalar.to_i
                      else
                        bottom_scalar.to_f
                      end

      @scalar /= bottom_scalar

      @numerator   ||= UNITY_ARRAY
      @denominator ||= UNITY_ARRAY
      @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if top
      @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if bottom

      # eliminate all known terms from this string.  This is a quick check to see if the passed unit
      # contains terms that are not defined.
      used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(%r{[\d\*, "'_^\/\$]}, '')
      raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty?

      @numerator = @numerator.map do |item|
        @@prefix_map[item[0]] ? [@@prefix_map[item[0]], @@unit_map[item[1]]] : [@@unit_map[item[1]]]
      end.flatten.compact.delete_if(&:empty?)

      @denominator = @denominator.map do |item|
        @@prefix_map[item[0]] ? [@@prefix_map[item[0]], @@unit_map[item[1]]] : [@@unit_map[item[1]]]
      end.flatten.compact.delete_if(&:empty?)

      @numerator = UNITY_ARRAY if @numerator.empty?
      @denominator = UNITY_ARRAY if @denominator.empty?
      self
    end
parse a string into a unit object.
 Typical formats like :
  "5.6 kg*m/s^2"
  "5.6 kg*m*s^-2"
  "5.6 kilogram*meter*second^-2"
  "2.2 kPa"
  "37 degC"
  "1"  -- creates a unitless constant with value 1
  "GPa"  -- creates a unit with scalar 1 with units 'GPa'
  6'4"  -- recognized as 6 feet + 4 inches
  8 lbs 8 oz -- recognized as 8 lbs + 8 ounces
 @return [nil | Unit]
 @todo This should either be a separate class or at least a class method