protected function process(array &$symbols, array $digits) {
    // Reverse all data, because we want to process numbers away from the
    // decimal separator.
    $symbols = array_reverse($symbols);
    $digits = array_reverse($digits);

    $last_digit_placeholder_i = 0;
    $last_optional_digit_placeholder_i = 0;
    foreach ($symbols as $i => $symbol) {
      if ($this->symbolIsSpecial($symbol, array(self::SYMBOL_DIGIT, self::SYMBOL_DIGIT_OPTIONAL))) {
        $last_digit_placeholder_i = $i;
      }
      if ($this->symbolIsSpecial($symbol, array(self::SYMBOL_DIGIT_OPTIONAL))) {
        $last_optional_digit_placeholder_i = $i;
      }
    }
    $last_grouping_size = 0;
    $current_grouping_size = 0;
    $last_digit_i = 0;
    foreach ($symbols as $i => $symbol) {
      // Replace placeholders, but only if we still have digits left to replace
      // them with.
      if ($digits && $this->symbolIsSpecial($symbol, array(self::SYMBOL_DIGIT, self::SYMBOL_DIGIT_OPTIONAL))) {
        // This is the last placeholder, so replace it with all remaining digits.
        if ($i == $last_digit_placeholder_i) {
          // If the pattern uses groupings, group remaining digits before
          // adding them.
          if ($last_grouping_size) {
            // Make sure the current grouping is full.
            while ($current_grouping_size < $last_grouping_size) {
              $symbol->replacement = array_shift($digits) . $symbol->replacement;
              $current_grouping_size++;
            }
            // If there are still digits left, add them as new groupings.
            if ($digits) {
              $chunks = $this->str_split(implode($digits), $last_grouping_size);
              foreach (array_reverse($chunks) as $chunk) {
                array_splice($symbols, $i + 1, 0, array(new NumberPatternSymbol(strrev($chunk))));
                array_splice($symbols, $i + 1, 0, array(new NumberPatternSymbol(self::SYMBOL_SPECIAL_GROUPING_SEPARATOR)));
              }
              // We processed all digits, so clear the array.
              $digits = array();
            }
          }
          // The pattern does not use groupings, so add all digits without
          // formatting.
          else {
            $symbol->replacement = strrev(implode($digits));
          }
        }
        // This is not the last placeholder, so replace it with a single digit.
        else {
          $symbol->replacement = array_shift($digits);
          $current_grouping_size++;
        }
        $last_digit_i = $i;
      }
      // Keep track of the last grouping size.
      elseif ($this->symbolIsSpecial($symbol, array(self::SYMBOL_SPECIAL_GROUPING_SEPARATOR))) {
        $last_grouping_size = $current_grouping_size;
        $current_grouping_size = 0;
      }
    }

    // Removes the last optional digit placeholder and everything between that
    // symbol and the last inserted digit.
    while ($last_optional_digit_placeholder_i > $last_digit_i) {
      unset($symbols[$last_optional_digit_placeholder_i]);
      $last_optional_digit_placeholder_i--;
    }

    // Put the symbols back in the order we received them in.
    $symbols = array_reverse($symbols);
  }