AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 29.04.2009, 11:28   #1  
valentino is offline
valentino
Участник
Аватар для valentino
 
33 / 11 (1) +
Регистрация: 14.02.2007
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Например, меня вполне устраивает в качестве разделителя тысяч пробел. Менять его на символ из панели управления не вижу смысла. Почему это не устраивает вас? В чем проблема-то?
Может я недостаточно четко сформулировал вначале, суть сводится к следующему:
при стандартных региональных настройках в панели управления, преобразование из числа в строку а затем из строки в число работает некорректно:
X++:
s = num2str(123456.78, 10, 2, -1, -1);    // s ="123 456.78"  (с пробелом, код которого = 32)
num = str2num(s);    // num = 123, в то время как ожидалось 123456.78  !!!
а попытка удалить из текстового представления тысячный разделитель (это может быть не только пробел) ни к чему не приводит, т.к. в данный момент в региональных настройках символ тысячного разделителя - это пробел с кодом 160! (см. первый джоб в начале темы)
Старый 29.04.2009, 12:28   #2  
in.dc is offline
in.dc
Участник
 
29 / 53 (2) ++++
Регистрация: 09.04.2009
strrem vs strkeep
Цитата:
Сообщение от valentino
X++:
s = strrem(s, thousandsSeparator);              // ничего не происходит
Цитата:
Сообщение от valentino Посмотреть сообщение
X++:
s = num2str(123456.78, 10, 2, -1, -1);    // s ="123 456.78"  (с пробелом, код которого = 32)
num = str2num(s);    // num = 123, в то время как ожидалось 123456.78  !!!
а попытка удалить из текстового представления тысячный разделитель (это может быть не только пробел) ни к чему не приводит, т.к. в данный момент в региональных настройках символ тысячного разделителя - это пробел с кодом 160! (см. первый джоб в начале темы)
А если рассмотреть вопрос с удалением символа 'разделителя тысяч' с другой позиции: т.е. не пытаться удалить (strrem) конкретный символ, а оставить в строке (содержащией числа) только допустимые с точки зрения Ax числовые символы (strkeep)?

X++:
static void jobRemoveThousandsSeparator(Args _args)
{
    #define.Numerics( ',.+-0123456789e' )
    str     s = num2str( 123456.78, 10, 2, -1, -1 ) ;
    real    num = str2num( strkeep( s, #Numerics ) ) ;
    ;

    info( strfmt( "%1", num ) ) ;
}
UPD: Oops, немного опоздал.
Изображения
 
__________________
Dynamics AX 4.0 SP2

Последний раз редактировалось in.dc; 29.04.2009 в 12:34. Причина: вариант с strkeep чуть раньше упомянул Hyper
За это сообщение автора поблагодарили: valentino (1).
Старый 29.04.2009, 19:09   #3  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,712 / 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++ не получилось, поскольку они съедают строки-комментарии в начале кода
Старый 30.04.2009, 09:28   #4  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Попробую еще раз.

МОЕ ПОНИМАНИЕ ПРОБЛЕМЫ:
Цитата:
Сообщение от valentino Посмотреть сообщение
Возникла проблема преобразования из текстового представления числа в само число, т.е. из "123 456.78" в 123456.78.
...
Текстовое представлене числа изначально в Аксапте формируется с помощью функции strfmt("%1", число).
МОЕ РЕШЕНИЕ ПРОБЛЕМЫ:
Цитата:
Сообщение от Gustav Посмотреть сообщение
Функция strFmt возвращает в виде строки ... real-число - с двумя десятичными знаками ... можно оставить в строке только 10 цифровых символов и знак "минус". Далее полученную строку конвертнуть обратно в число ... "обманув" ... и разделитель тысяч, и десятичную точку (запятую):
... и окончательный вариант "обмана" выглядит так (без предыдущего, возможно кого-то пугающего, деления на 100):
X++:
static void Job173(Args _args)
{
    real a = 123456.78;
    str  strNumberAfterStrFmt = strFmt('%1', a);
    real b;
    boolean c;
    ;

    b = str2Num(
        strFmt ( '%1e-2',
        strKeep( strNumberAfterStrFmt, '-0123456789')));

    c = a == b;
    box::info(strFmt('%1\n\n%2\n\n%3',
        strFmt('Исходное число: %1', a),
        strFmt('Восстановленное число из строки: %1', b),
        strFmt('Исходное число равно числу из строки?: %1', c)));
}
P.S.
В процессе эксперимента обратил внимание на то, что региональные настройки Аксапта считывает при старте приложения и далее в текущей сессии их не меняет (!) даже при изменении региональных настроек в панели управления. Такое поведение Аксапты отличается, например, от поведения Excel, где при смене локали c Russian на English (United States) наглядно видно, как в ячейке тут же меняются разделители тысяч с пробелов на запятые.

Последний раз редактировалось Gustav; 30.04.2009 в 09:42.
За это сообщение автора поблагодарили: aidsua (1).
Теги
разделитель тысячных, axapta

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Разделитель страницы в MS WORD FiGr DAX: Программирование 3 14.05.2007 15:24
Разделитель десятичных знаков в отчетах dirigente DAX: Функционал 0 20.11.2003 12:28
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 14:37.