Как изменить формат данных передаваемых из Excel?

Пишу программу, которая работает с Excel файлом.
Задача - прочитать его содержимое и записать это в массив.
Всё работает, но часть данных, при записи в массив искажается. При чтении из определенного столбца.
Например - Excel в файле (в столбце) написано 6651440820000450, а в массив поступает значение 6,67716087900069E+15.
В Excel в файле, ячейки этого столбца имеют тип - числовой.
Причем другие подобные ячейки, содержащие менее длинные числа, записываются в массив правильно, без искажения.
Как это исправить?

Часть кода
var
Ap:Variant; //Переменная excel файла
TABLE_list_1 : array of array [1..50] of string; //Массив

begin
Ap:=CreateOleObject('Excel.Application'); //Создаем объект
Ap.Workbooks.Open(input_file_path,0,True); //Открываем файл для чтения
Ap.DisplayAlerts:=False; //Отключаем любые сообщения excel

SetLength(TABLE_list_1, 1000000); //Указываем размер массива 
//Он не динамический т.к. в Delphi 7 есть ошибка при больших динамических массивах

//Передаем содержимое ячейки Excel в элемент массива
for i:=1 to 50 do
begin
for j:=1 to 50 do
begin
TABLE_list_1[TABLE_list_1_records_count,j]:=Ap.Cells[i,TABLE_list_1_column_number[j]];
end;
end;
Ap.Application.Quit; //Закрываем excel файл
  • Вопрос задан
  • 363 просмотра
Пригласить эксперта
Ответы на вопрос 2
@Mercury13
Программист на «си с крестами» и не только
Плавали, знаем. В массив поступает как раз то, что нужно. Причина в алгоритмах конвертации число→строка, и надо добавить такую штуку:
«Если число — по типу Double, по факту точное целое и находится в определённых пределах, преобразовать его в Int64, а затем Int64 в строку».

Сама проверка, является ли double точным целым, довольно сложна. У меня есть код для этого на Си++ (который, в свою очередь, является портом кода из Java). Портанёте на Delphi сами?

enum {
    DOUBLE_MANTISSA_BITS = 52,
    DOUBLE_MIN_EXPONENT = -1022,
    DOUBLE_EXPONENT_BIAS = 1023,
};

#define UC8x(X,Y,Z,T) (static_cast<uint64_t>(0x##X##Y##Z##T##ULL))
#define DOUBLE_MANTISSA_MASK     UC8x(000f, ffff, ffff, ffff)
#define DOUBLE_EXPONENT_MASK     UC8x(7ff0, 0000, 0000, 0000)
#define DOUBLE_EXPONENT_MASK_HI  UC4x(7ff0, 0000)
#define DOUBLE_IMPLICIT_BIT (DOUBLE_MANTISSA_MASK + 1)

    union DoubleInt {
        double asDouble;
        uint64_t asInt;
        struct {
            uint32_t lo, hi;
        } asIntel;
    ....
   }

    int DoubleInt::exponent() const
    {
        return static_cast<int>((
                      static_cast<int64_t>(asInt & DOUBLE_EXPONENT_MASK) >>
                      (DOUBLE_MANTISSA_BITS)) - DOUBLE_EXPONENT_BIAS);
    }

    uint64_t DoubleInt::unsafeMantissa() const
    {
        int ex = exponent();
        uint64_t bits = asInt & DOUBLE_MANTISSA_MASK;
        return (ex == DOUBLE_MIN_EXPONENT - 1)
          ? bits << 1
          : bits | DOUBLE_IMPLICIT_BIT;
    }

    bool DoubleInt::isPreciseInteger() const
    {
        // функцию isFinite() намеренно упустил, ибо она есть «в коробке» Delphi.
        // А вот в Си++ есть не во всех реализациях…
        return isFinite()
            && (asDouble == 0.0 ||
            DOUBLE_MANTISSA_BITS - numberOfTrailingZeros(unsafeMantissa()) <= exponent());
    }

int math::numberOfTrailingZeros(uint64_t i)
{
    uint32_t x, y;
    if (i == 0u) return 64;
    int n = 63;
    y = static_cast<uint32_t>(i);
    if (y != 0) { n = n -32; x = y; } else x = (int)(i >> 32);
    y = x << 16; if (y != 0) { n = n -16; x = y; }
    y = x << 8;  if (y != 0) { n = n - 8; x = y; }
    y = x << 4;  if (y != 0) { n = n - 4; x = y; }
    y = x << 2;  if (y != 0) { n = n - 2; x = y; }
    return n - ((x << 1) >> 31);
}

bool math::isPreciseInteger(double x)
{
    DoubleInt di;
    di.asDouble = x;
    return di.isPreciseInteger();
}


Может быть, вам сработают и упрощённые варианты вроде «столбец X — преобразовать в Int64, затем в целое». В промышленной программе этого не хватало.
Ответ написан
Комментировать
@kalapanga
var
  x: Int64;
...
  x := Ap.Cells[i,j];
  TABLE_list_1[i,j]:=IntToStr(x);
...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы