Цитата:
Сообщение от
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++ не получилось, поскольку они съедают строки-комментарии в начале кода