You are here

function parse_formatted_number in Format Number API 7

Same name and namespace in other branches
  1. 6 format_number.module \parse_formatted_number()

Parse a formatted number.

This function implements lenient parsing when possible, and only falls back to site/user defined symbols when in doubt. See http://www.unicode.org/reports/tr35/tr35-11.html#Lenient_Parsing

@todo The algorithm probably needs optimization (using regular expressions?).

Parameters

string $formatted_number: A number formatted with localized thousands separator and decimal point.

boolean $required: If input is empty string, return FALSE when number is strictly required, otherwise an empty string is returned as 0.

Return value

number A valid PHP number. FALSE when input cannot be deciphered.

3 calls to parse_formatted_number()
format_number_numericfield_process in ./format_number.module
Process an individual numeric form element.
format_number_numericfield_validate in ./format_number.module
Validation of an individual numeric form element.
form_type_numericfield_value in ./format_number.module
Helper function to determine the value for a numeric form element.

File

./format_number.module, line 244
This module provides a method to configure number formats (site default and user defined) with configurable decimal point and thousand separators. It also exposes several functions that can be used by other contributed or custom modules to display…

Code

function parse_formatted_number($formatted_number, $required = TRUE) {
  static $format_options, $decimal_point_options, $thousands_separator_options;
  if (!isset($format_options)) {
    $format_options = format_number_get_options();
    $decimal_point_options = format_number_get_decimal_point_options();
    $thousands_separator_options = format_number_get_thousands_separator_options();
  }

  // Trim input.
  $formatted_number = trim($formatted_number);
  if ($formatted_number === '') {
    return $required ? FALSE : 0;
  }

  // When no-break space is the site/user defined thousands separator, then
  // ascii space may also be accepted.
  if ($format_options['thousands_sep'] == " ") {
    $thousands_separator_options[' '] = TRUE;
  }

  // Extract the sign.
  $is_negative = FALSE;
  if ($formatted_number[0] == '-' || $formatted_number[0] == '+') {
    $is_negative = $formatted_number[0] == '-' ? TRUE : FALSE;
    $formatted_number = drupal_substr($formatted_number, 1);
  }
  else {
    $last_char = $formatted_number[drupal_strlen($formatted_number) - 1];
    if ($last_char == '-' || $last_char == '+') {
      $is_negative = $last_char == '-' ? TRUE : FALSE;
      $formatted_number = drupal_substr($formatted_number, 0, -1);
    }
  }

  // Extract non-numeric symbols.
  preg_match_all('#[^0-9]#u', $formatted_number, $matches);
  $non_numeric_symbols = array_count_values($matches[0]);
  $non_numeric_symbols_count = count($non_numeric_symbols);
  if ($non_numeric_symbols_count > 2) {

    // More than two different non-numeric symbols.
    return FALSE;
  }

  // When 2 non-numeric symbols are present, the first one should be the
  // thousands separator, the second one should be a decimal separator.
  if ($non_numeric_symbols_count == 2) {

    // Extract and validate thousands separator.
    $thousands_sep = array_keys($non_numeric_symbols);
    $thousands_sep = array_shift($thousands_sep);
    if (!isset($thousands_separator_options[$thousands_sep])) {

      // This is not a valid thousands separator symbol.
      return FALSE;
    }

    // Strip out thousands separators.
    $formatted_number = str_replace($thousands_sep, '', $formatted_number);

    // Extract and validate decimal point.
    unset($non_numeric_symbols[$thousands_sep]);
    $decimal_point = array_keys($non_numeric_symbols);
    $decimal_point = array_shift($decimal_point);
    if ($non_numeric_symbols[$decimal_point] > 1) {

      // Decimal point symbol is used more than once.
      return FALSE;
    }
    if (!isset($decimal_point_options[$decimal_point])) {

      // This is not a valid decimal point symbol.
      return FALSE;
    }

    // Convert decimal point into dot, if necessary.
    if ($decimal_point != '.') {
      $formatted_number = str_replace($decimal_point, '.', $formatted_number);
    }
  }
  elseif ($non_numeric_symbols_count == 1) {
    $unknown_symbol = array_keys($non_numeric_symbols);
    $unknown_symbol = array_shift($unknown_symbol);

    // When unknown symbol is used more than once, it can only be a
    // thousands separator, but it should be valid one.
    if ($non_numeric_symbols[$unknown_symbol] > 1) {
      if (!isset($thousands_separator_options[$unknown_symbol])) {

        // This symbol is not a valid thousands separator.
        return FALSE;
      }

      // Strip out unknown symbol (aka. thousands separators in this case).
      $formatted_number = str_replace($unknown_symbol, '', $formatted_number);
    }
    elseif ($unknown_symbol != '.' && $unknown_symbol != ',') {
      if (isset($decimal_point_options[$unknown_symbol])) {

        // This is a valid decimal point symbol.
        $formatted_number = str_replace($unknown_symbol, '.', $formatted_number);
      }
      if (isset($thousands_separator_options[$unknown_symbol])) {

        // This is a valid thousands separator symbol.
        $formatted_number = str_replace($unknown_symbol, '', $formatted_number);
      }
      else {

        // This is an invalid symbol.
        return FALSE;
      }
    }
    else {
      if ($unknown_symbol == $format_options['decimal_point']) {

        // This is a valid decimal point symbol.
        $formatted_number = str_replace($unknown_symbol, '.', $formatted_number);
      }
      elseif ($unknown_symbol == $format_options['thousands_sep']) {

        // This is a valid thousands separator symbol.
        $formatted_number = str_replace($unknown_symbol, '', $formatted_number);
      }
      else {

        // This is an invalid symbol.
        return FALSE;
      }
    }
  }
  return ($is_negative && 0 != $formatted_number ? '-' : '') . $formatted_number;
}