Показать сообщение отдельно
Старый 29.04.2009, 19:09   #14  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,713 / 1201 (44) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от valentino Посмотреть сообщение
Может я недостаточно четко сформулировал вначале, суть сводится к следующему:
при стандартных региональных настройках в панели управления, преобразование из числа в строку а затем из строки в число работает некорректно:
X++:
s = num2str(123456.78, 10, 2, -1, -1);    // s ="123 456.78"  (с пробелом, код которого = 32)
num = str2num(s);    // num = 123, в то время как ожидалось 123456.78  !!!
а попытка удалить из текстового представления тысячный разделитель (это может быть не только пробел) ни к чему не приводит, т.к. в данный момент в региональных настройках символ тысячного разделителя - это пробел с кодом 160! (см. первый джоб в начале темы)
Хорошо. А сама задача-то в чем заключается? С какой целью надо "ходить по кругу"?

Вы описали бессмысленную, с моей точки зрения, задачу. Преобразовать число в строку, а затем из полученной строки снова сделать число. Зачем? Почему нельзя было взять исходной число без этих преобразований?

Есть правила перевода числа в строку. Есть правила перевода строки в число. Эти правила вовсе не обязаны быть взаимно-однозначны. Могут, но не обязательно.

Попробуйте сформулировать, хотя бы для самого себя, какова конечная цель?

Вы хотите, чтобы алгоритмы преобразования число-строка и строка-число были взаимно-однозначны? По каким правилам? Почему правила должны быть именно такими?

Или вам надо преобразовать вполне конкретную символьную строку (сформированную по определенным правилам) в число?

Если стоит всего-лишь вторая задача, то посмотрите мой пример преобразования символьной строки в число. Алгоритм достаточно сложен. А ведь я это писал под вполне конкретную задачу. Хотя и постарался сделать код, по-возможности, достаточно универсальным.

Код:
// Конвертация символьной строки в число

// Данный метод не анализирует возможность того, что один из разделителей может являться частью другого
// Например, разделитель целой и дробной части - это две точки подряд, а разделитель троек цифр - одна точка
// Последствия использования подобных разделителей в данном методе могут быть парадоксальными (не ожидАемыми)


//    Примеры вызова
/*
    print global::rtg_str2num("123.45");                // 123.45
    print global::rtg_str2num("1 234 567.89");          // 1234567.89
    print global::rtg_str2num("1 234 567.89e-2");       // 12345.6789
    print global::rtg_str2num("1 234 567,89",",");      // 1234567.89
    print global::rtg_str2num("123,5","","",",");       // 123e5 = 12 300 000
    print global::rtg_str2num("123.4,1","","",",");     // 123.4e1 = 1234
    print global::rtg_str2num("123e4.1","e","",".");    // 123.4e1 = 1234
    print global::rtg_str2num("123e4","e","",".");      // 123.4
    pause;
    return;

*/

#define.point(".")
#define.separator(" ")
#define.base("e")

public static real rtg_str2num( str _string,                    // собственно строка, которую надо перевести "123 456.78"
                                str _point      = #point,       // разделитель целой и дробной части
                                str _separator  = #separator,   // разделитель троек цифр
                                str _base       = #base         // Основание. Разделитель мантиссы и порядка числа, если оно представлено в форме "123e-2"
                                )
{

    ;

    // Как правило, параметр не указывают, если хотят указать значение параметра, следующего за ним,
    // а значение пропущенного параметра предполагается считать значением по умолчанию
    if (! _point)
    {
        _point = #point;
    }
    if (! _separator)
    {
        _separator = #separator;
    }
    if (! _base)
    {
        _base = #base;
    }

    // Ситуация, когда разные разделители имеют одно и то же значение рассматривается как ошибка,
    // поскольку становится невозможно выделить нужные части строки
    if (_point == _separator)
    {
        throw error(strFmt("Разделитель целой и дробной части \"%1\" не может быть равен разделителю троек цифр \"%2\"",_point, _separator));
    }

    if (_point == _base)
    {
        throw error(strFmt("Разделитель целой и дробной части \"%1\" не может быть равен разделителю мантиссы и порядка числа \"%2\"",_point, _base));
    }

    if (_separator == _base)
    {
        throw error(strFmt("Разделитель троек цифр \"%1\" не может быть равен разделителю мантиссы и порядка числа \"%2\"",_separator, _base));
    }


    // Удаляю ведущие и концевые пробелы
    // Вообще все пробелы удалять нельзя, поскольку какой-либо символ разделитель может содержать или быть пробелом
    // Хотя, в принципе, эту операция можно вообще не делать, поскольку функции str2num() эти пробелы не мешают
    _string = global::strLRTrim(_string);

    // Удаляю символы разделители троек цифр
    if (_separator)
    {
        if (strLen(_separator) == 1)
        {
            _string = strRem(_string, _separator);
        }
        else
        {
            // Здесь strRem() использовать нельзя, поскольку необходимо удалить именно
            // определенную последовательность символов, а не отдельные символы
            _string = global::strReplace(_string, _separator, "");
        }
    }

    // Если необходимо сделать две последовательные замены одного набора символов на другой,
    // то необходимо убедтиться в том, что вторая замена не "затрет" результат первой
    // т.е. в результате первой замены не должны появиться символы, которые заменит вторая замена
    switch (true)
    {
    case ((_base != #base) && (_point != #point) && (_point == #base) && (_base == #point)) :
        // Здесь нужна промежуточная замена на символы, которые не равны ни _point, ни _base
        // Подойдет _separator, поскольку это значение уже было проверено на данное равенство
        // и последовательность символов _separator была удалена из строки
        _string = global::strReplace(_string, _base, _separator);
        _string = global::strReplace(_string, _point, #point);
        _string = global::strReplace(_string, _separator, #base);
        break;
    case ((_base != #base) && (_point != #point) && (_point == #base)) :
        _string = global::strReplace(_string, _point, #point);
        _string = global::strReplace(_string, _base,  #base);
        break;
    case ((_base != #base) && (_point != #point) && (_base == #point)) :
        _string = global::strReplace(_string, _base,  #base);
        _string = global::strReplace(_string, _point, #point);
        break;
    default :
        if (_point != #point)
        {
            _string = global::strReplace(_string, _point, #point);
        }
        if (_base != #base)
        {
            _string = global::strReplace(_string, _base,  #base);
        }
        break;
    }


    return str2num(_string);

}
PS: использовать теги X++ не получилось, поскольку они съедают строки-комментарии в начале кода