Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Проблема у меня не большая!!


Автор: JokeR.StR 7.1.2008, 04:56
Вот на днях понадобилось перевести из string в double или real а не получилось! 
Так значит что я делал:
Код
procedure TForm1.FormCreate(Sender: TObject);
var i:double;
    s:string;
begin
s:='12.32';
i:=strtofloat(s);
end;

Заместо double писал и real но угу все равно не поучается!! Выдает ошибку типа 12.32 не может быть этим числом(ну типа того).
А вот если вот так:
Код
procedure TForm1.FormCreate(Sender: TObject);
var i:double;
begin
i:=12.32;
end;

То вот так все работает!! Помогите плз!!


M
Alexeis
Модератор: Название темы должно отражать ее суть! В следующий раз просто закрою тему.

Автор: aktuba 7.1.2008, 07:25
Поменяй точку на запятую.

Автор: JokeR.StR 7.1.2008, 13:57
Цитата(aktuba @ 7.1.2008,  05:25)
Поменяй точку на запятую.

Так когда я просто присваиваю у меня же присваивание идет!!

Автор: Данкинг 7.1.2008, 14:23
Цитата(JokeR.StR @ 7.1.2008,  13:57)
Цитата(aktuba @ 7.1.2008,  05:25)
Поменяй точку на запятую.

Так когда я просто присваиваю у меня же присваивание идет!!

А почему тогда просто присваивать нельзя? А вообще лучше действительно запятую сделать вместо точки. И чтобы в "региональных стандартах" тоже в качестве разделителя запятая стояла.

Автор: remax 7.1.2008, 14:30
используй константу decimalseparator в ней записан символ десятичного разделителя из региональных стандартов".

Код

procedure TForm1.FormCreate(Sender: TObject);
var i:double;
    s:string;
begin
s:='12.32';
for i:=1 to length(s) do
  if pos (s[i],'.,')>0
     then s[i]:=decimalseparator;
i:=strtofloat(s);
end


Добавлено через 6 минут и 13 секунд
Цитата(JokeR.StR @ 7.1.2008,  10:57)
Цитата(aktuba @ 7.1.2008,  05:25)
Поменяй точку на запятую.

Так когда я просто присваиваю у меня же присваивание идет!!

Не надо путать строки и вещественные числа. При работе с вещественными числами всегда (!) в качестве разделителя используется точка. А при преобразовании из строки в число в качестве разделителя используется символ  из "региональных стандартов".

Автор: JokeR.StR 7.1.2008, 14:38
Всем большое спасибо!!

Автор: Poseidon 7.1.2008, 15:01
remax, фиговый у тебя пример smile

Код
procedure TForm1.FormCreate(Sender: TObject);
var 
i:double;
s:string;
begin
s:= StringReplace('12.32', '.', DecimalSeparator, [rfReplaceAll]);
i:=StrToFloat(s);
end;


только нафига тут i надо?

Автор: MetalFan 7.1.2008, 15:14
забанить бы автора за такой заголовок темы...

Автор: remax 7.1.2008, 15:40
Цитата(Poseidon @ 7.1.2008,  12:01)
remax, фиговый у тебя пример smile

Код
procedure TForm1.FormCreate(Sender: TObject);
var 
i:double;
s:string;
begin
s:= StringReplace('12.32', '.', DecimalSeparator, [rfReplaceAll]);
i:=StrToFloat(s);
end;


только нафига тут i надо?

Гы. Посмотри внимательно на свой и на мой пример.
У меня универсально. Что бы не было в исходной строке (точка или запятая), какая бы не была региональная настройка (точка или запятая) - сработает правильно. У тебя допустимы только точки в исходной строке.
Вот и вся разница.
А переменная i и так уже объявлена.  smile 

Автор: Poseidon 7.1.2008, 16:48
Цитата(remax @  7.1.2008,  15:40 Найти цитируемый пост)
У меня универсально. Что бы не было в исходной строке (точка или запятая), какая бы не была региональная настройка (точка или запятая) - сработает правильно. 
В исходной строке у тебя тоже точка. Она в пятой строчке твоего кода  прописана smile Поэтому нет смысла искать запятую в троке в которой точно известно что стоит точка.

Цитата(remax @  7.1.2008,  15:40 Найти цитируемый пост)
А переменная i и так уже объявлена.

Она объявлена, это да. Только: 
Цитата(Poseidon @  7.1.2008,  15:01 Найти цитируемый пост)
нафига тут i надо? 


Автор: remax 7.1.2008, 18:02
Исходный пример легко модифицируется с преобразования строковой константы на строковую переменную или скажем свойство TEXT, компонента TEDIT. 
А писать программы надо так, чтобы легкая модификация не приводила бы к необходимости перелопачивать весь исходник. И учитывая явную неопытность автора темы в программировании имеет смысл показать ему более надежный и универсальный пример. Хотя, 100% надежности не бывает. Скажем, две точки в строке - однозначно фатал.

P.S. На мой взгляд тут все прозрачно и очевидно. Странно, что опытный Delphi developer  этого не видит.

Добавлено через 4 минуты и 41 секунду
Не мог удержаться, чтобы не добавить. smile 


А с точки  зрения  эффективности, что предпочтительней использовать 
Код

function StringReplace(const S, OldPattern, NewPattern: string;
  Flags: TReplaceFlags): string;
var
  SearchStr, Patt, NewStr: string;
  Offset: Integer;
begin
  if rfIgnoreCase in Flags then
  begin
    SearchStr := AnsiUpperCase(S);
    Patt := AnsiUpperCase(OldPattern);
  end else
  begin
    SearchStr := S;
    Patt := OldPattern;
  end;
  NewStr := S;
  Result := '';
  while SearchStr <> '' do
  begin
    Offset := AnsiPos(Patt, SearchStr);
    if Offset = 0 then
    begin
      Result := Result + NewStr;
      Break;
    end;
    Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
    NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
    if not (rfReplaceAll in Flags) then
    begin
      Result := Result + NewStr;
      Break;
    end;
    SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
  end;
end;



или

Код

for i:=1 to length(s) do
  if pos (s[i],'.,')>0
     then s[i]:=decimalseparator;






Автор: JokeR.StR 7.1.2008, 21:43
Да я уже заменил 
Код
for i:=1 to length(s) do
  if pos (s[i],'.,')>0
     then s[i]:=decimalseparator;

Про это я сам давно знал и этим воспользовался!!

Автор: source777 8.1.2008, 00:31
Цитата(remax @ 7.1.2008,  16:02)
Не мог удержаться, чтобы не добавить. smile 


А с точки  зрения  эффективности, что предпочтительней использовать 
...

Естественно StringReplace, причём не только с точки зрения эффективности, но и с точки зрения разумности...
Если не веришь проверь, StringReplace опережает по быстродействию твой вариант в 1,5 раза
Код

procedure TForm1.Button1Click(Sender: TObject);
const N=1000000;
var t0, t1, t2, t3: Cardinal;
i,j: integer;
s, s0: string;
begin
  s0:=\\\'124515.2351636\\\';
  s:=s0;

  t0:=GetTickCount;
  for i:=1 to N do
  begin
    s:=s0;
  end;
  t1:=GetTickCount-t0;

  t0:=GetTickCount;
  for i:=1 to N do
  begin
    s:= StringReplace(s0, \\\'.\\\', DecimalSeparator, [rfReplaceAll]);
  end;
  t2:=GetTickCount-t0;

  t0:=GetTickCount;
  for i:=1 to N do
  begin
    s:=s0;
    for j:=1 to length(s0) do
    if pos (s0[j],\\\'.,\\\')>0
      then s[j]:=decimalseparator;
  end;
  t3:=GetTickCount-t0;

  Label1.Caption:=IntToStr(t2-t1)+#13+IntToStr(t3-t1);
end;


P.S. Не могу не добавить: Нет большего зла в программировании, чем преждевременная оптимизация, тем более неумелая!!!

Добавлено @ 00:36
Кстати если расширить вариант со StringReplace до 
Код

    sep:=\\\'.\\\';
    if (DecimalSeparator=sep) then sep:=\\\',\\\';
    s:= StringReplace(s0, sep, DecimalSeparator, [rfReplaceAll]);

Это фактически не скажется на быстродействии, и StringReplace побеждает с тем же результатом (быстрее в 1,5 раза) и с тем же уровнем гибкости... smile 

Автор: remax 8.1.2008, 01:29
гы. А ты, для интереса, замени s0:='124515.2351636'; на скажем, s0:='5.2';  smile 

И мой вариант будет ровно в 2 раза быстрее...

да, забыл сказать, убери строку 27 - не спортивно по мелочам махлевать.
 
Скажу даже больше, до длины исходной строки 9 символов включительно мой вариант быстрее.
Начиная с 10 твой начинает обгонять. Так что не надо огульно так обвинять в неумелой оптимизации...

Добавлено через 11 минут и 4 секунды
И чтобы окончательно закрыть тему, надо делать так:
Код

    j:=pos ('.',s0);
    if j=0 then j:=pos (',',s0);
    if j<>0 then s[j]:=decimalseparator;


По быстродействию это будет примерно в 50 раз быстрее всех предыдущих вариантов. 

Автор: Yanis 8.1.2008, 01:52
source777, remax
Ребят идите… в аську. Или на крайняк в почту/PM. 
Ваши замеры совсем не по теме тут уже smile

P. S. Cогласен с MetalFan.

Автор: remax 8.1.2008, 01:57
Ну вот, а как же истина?

все-все ухожу.....   smile 

Автор: source777 8.1.2008, 16:32
Цитата

да, забыл сказать, убери строку 27 - не спортивно по мелочам махлевать.

она необходима, чтобы на каждой итерации было что менять, так что всё спортивно...

Цитата

И чтобы окончательно закрыть тему, надо делать так:

Гы, это ты уже какую-то другую задачу решил, изначально все вхождения заменяли, так что нечего даже сравнивать решения двух разных задач...

А оптимизация всё же неумелая(так и быть докажу, чтоб не огульно было), ибо нижеследующий код, решая исходную задачу, работает на порядок быстрее и StringReplace, и твоей горе-оптимизации... 
Код

    sep:=\'.\';
    if (DecimalSeparator=sep) then sep:=\',\';
    for j:=1 to length(s0) do
      if (s0[j]=sep) then s[j]:=DecimalSeparator;

Однако, необходимо заметить, что если замену надо выполнить для менее чем тысячи строк подряд, то StringReplace предпочтительнее, ибо оптимизация подобного кода будет не нужна по практическим соображениям, а читабельность будет страдать... 
А вместо того, чтобы признать тот факт, что ты не знаешь стандартных функций, ты попытался свалить всё на мнимую оптимизацию... 

Цитата

source777, remax
Ребят идите… в аську. Или на крайняк в почту/PM. 
Ваши замеры совсем не по теме тут уже 

Почему же, пусть человек узнает несколько решений, и поймёт как надо, а как не надо программировать и почему именно так.

P.S. Кстати мериться начал remax, с неуместного наезда на разработчиков Delphi...

Автор: remax 8.1.2008, 19:29
Не согласен с твоими утверждениями, но, по просьбе Yanisа, дискуссию перенес в почту. Читай в личке...

Автор: New Neon 8.1.2008, 23:02
А вот самый оптимальный помоему вариант:
Код

procedure TForm1.Button1Click(Sender: TObject);
var
    e:integer;
    s:string;
    d:double;
begin
s:='12.32';
val(s,d,e);
if e>0 then s[e]:=DecimalSeparator;
try
  d:=StrToFloat(s);
except
  ShowMessage('Error !!! ');
end;
end;

и перевод и проверка smile.

Автор: remax 8.1.2008, 23:40
Оригинально, только не всегда работает. Дело в том, что строка для VAL всегда! (если мне не изменяет память) в качестве разделителя использует точку. Рассмотрим следующий вариант

decimalseparator=',';
s:='12.32';

 в результате после VAL d=0 (нет ошибки)
и замена не происходит.

Поэтому d:=StrToFloat(s); завершается ошибкой.

Автор: New Neon 8.1.2008, 23:48
Правильно мыслишь, тогда и заменять то не надо - переведенное значение уже в d. smile

Сори за погрешность исправляю : 
Код

procedure TForm1.Button1Click(Sender: TObject);
var
  e:integer;
  s:string;
  d:double;
begin
s:='12.32';
val(s,d,e);
if e>0 then 
begin
  s[e]:=DecimalSeparator;
  try
    d:=StrToFloat(s);
  except
    ShowMessage('Error !!! ');
  end;
end;
end;

Автор: remax 8.1.2008, 23:55
Да, согласен. Так работает.

Автор: MetalFan 9.1.2008, 11:16
Цитата(New Neon @  8.1.2008,  23:48 Найти цитируемый пост)
  try
    d:=StrToFloat(s);
  except
    ShowMessage('Error !!! ');
  end;

а чем TryStrToFloat не подходит?

Автор: New Neon 9.1.2008, 12:18
MetalFan, Согласен, твой вариант даже быстрее работать будет. smile
Как говориться "Век живи - век учись".

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)