Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Форум группы: delphi > Заменить млн на нули


Автор: Akella 27.9.2011, 22:32
Обрабатываю текстовые объявления, в которых указана цена.
Цены могут быть так указаны:
2,3 млн
2.3 млн
5 млн
Ну в общем как податель объявы захочет.

Из текста регуляркой ищу цену, например, 2,3 млн.

Теперь цену нужно сохранить в базу, в поле типа float или integer, т.е. без млн.

Вот такой у мну алгоритм.

Код

Var
  m: string;
  p: double;
...
begin
...
// на входе 2,3 млн

      if pos('МЛН', AnsiUpperCase(m)) <> 0 then
        begin
          //меняем "." или "," на разделитель
          m := StringReplace(m, ',', DecimalSeparator, [rfReplaceAll, rfIgnoreCase]);
          m := StringReplace(m, '.', DecimalSeparator, [rfReplaceAll, rfIgnoreCase]);

          //получаем 2.3 млн

          m := OnlyDec(m, DecimalSeparator);// удаляем всё, кроме цифр и разделителя (моя функция), получаем 2.3

          p := StrToFloatDef(m, 0);// конвертируем в double, чтобы умножить на [I]1 000 000[/I]

          p := p * 1000000;// получаем [I]2 300 000[/I]

          m := FloatToStr(p);// возвращаем правильное число
        end;// if pos('МЛН', AnsiUpperCase(m)) <> 0 then


Но слишком замудрёно и, наверняка, не самый быстрый способ.

Может кто решал подобные проблемы и подскажет более правильный и быстрый код?

Автор: de_Nis 28.9.2011, 12:37
Уважаемый Akella! Может быть, этой теме место в основном форуме Дельфи? smile 

Автор: Akella 28.9.2011, 12:53
Здесь как бы уже решение решение. В принципе вопроса как бы и нету  smile , но как бы и есть. Нужна только оптимизация кода, если она поможет. А этот раздел как раз для таких случаев smile

Автор: kemiisto 28.9.2011, 16:07
Цитата(Akella @  27.9.2011,  21:32 Найти цитируемый пост)
Может кто решал подобные проблемы и подскажет более правильный и быстрый код? 

Группировки надо использовать в регулярке. Показывай свою регулярку.

Автор: Akella 28.9.2011, 16:36
какие группировки?

Автор: kemiisto 28.9.2011, 23:32
Akella, даже http://forum.vingrad.ru/articles/topic-213075.html есть. Второй пример.

Автор: Keeper89 28.9.2011, 23:32
http://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#.D0.93.D1.80.D1.83.D0.BF.D0.BF.D1.8B

Автор: Akella 29.9.2011, 09:38
Да при чём здесь регулярки, если мну нужно правильно заменить 2,3 млн или 10 млн на 2,300000 и соответственно на 10000000?

Добавлено через 22 секунды
Про группировку и скобки я в курсе если чё

Автор: Keeper89 30.9.2011, 14:35
Akella:
Код

var
...
  IntP, FracP: Integer;
...
try
...
    RegExp.Expression := '(\d+)([.,])(\d+)';
    if RegExp.Exec('2,3 млн') then
    begin
      if TryStrToInt(RegExp.Match[1], IntP) and TryStrToInt(RegExp.Match[3], FracP) then  
        Result := FloatToStr(IntP * 1000000 + FracP * 100000);
    end
...

Как-то так, не тестировал. Но выглядит проще, чем твое.

Автор: Akella 30.9.2011, 14:39
Чем проще? Тем что я заменяю . или , на DecimalSeparator?

Ну и если у тебя попадётся какой-то мусор, то номер не пройдёт. А у меня этот мусор будет отсеян.

Автор: AndreyIQ 30.9.2011, 15:25
Цитата(Keeper89 @ 30.9.2011,  14:35)
Akella:
Код

var
...
  IntP, FracP: Integer;
...
try
...
    RegExp.Expression := '(\d+)([.,])(\d+)';
    if RegExp.Exec('2,3 млн') then
    begin
      if TryStrToInt(RegExp.Match[1], IntP) and TryStrToInt(RegExp.Match[3], FracP) then  
        Result := FloatToStr(IntP * 1000000 + FracP * 100000);
    end
...

Как-то так, не тестировал. Но выглядит проще, чем твое.

Интересно, что вернет Ваш код, если ввести 2,03 млн.
Цитата(Akella @ 27.9.2011,  22:32)
Обрабатываю текстовые объявления, в которых указана цена.
Но слишком замудрёно и, наверняка, не самый быстрый способ.

ИМХО проще некуда.
ЗЫ Что за код в OnlyDec?

Автор: CodeMonkey 30.9.2011, 21:14
Может StringReplace 'млн' -> 'x10^6' ?

Тогда строка '2,3 млн.' после замены будет читаться как '2,3 x 10 ^ 6', что есть 2'300'000.

Автор: Keeper89 30.9.2011, 22:08
Цитата(AndreyIQ @  30.9.2011,  15:25 Найти цитируемый пост)
Интересно, что вернет Ваш код, если ввести 2,03 млн.


Цитата(Akella @  30.9.2011,  14:39 Найти цитируемый пост)
Чем проще? Тем что я заменяю . или , на DecimalSeparator?

Это дело корректировки регулярки.

Если надо вообще коротко (?), то можно сделать типа того, что CodeMonkey предложил.

Автор: Akella 1.10.2011, 11:05
Цитата(CodeMonkey @ 30.9.2011,  21:14)
Может StringReplace 'млн' -> 'x10^6' ?

Тогда строка '2,3 млн.' после замены будет читаться как '2,3 x 10 ^ 6', что есть 2'300'000.

StringReplace не работает с цифрами или я не понял твоего примера.

Добавлено через 47 секунд
покажи пример на 5 млн, 10 млн и на 1.05 млн

Добавлено через 1 минуту и 37 секунд
Не забывайте, что это тексты объявлений и податель объявления может написать как ему моча в голову стукнет. Хот с точкой, хоть с запятой, хоть с двумя пробелами или без оных вообще. smile

Добавлено через 3 минуты и 12 секунд
Цитата(CodeMonkey @  30.9.2011,  21:14 Найти цитируемый пост)
'2,3 x 10 ^ 6',

Т.е. вот это потом перевести в число?
Код

i := StrToInt('2,3 x 10 ^ 6')

Автор: CodeMonkey 2.10.2011, 14:40
Цитата
StringReplace не работает с цифрами или я не понял твоего примера.

Добавлено через 47 секунд
покажи пример на 5 млн, 10 млн и на 1.05 млн


Код
S := '.... бла-бла-бла... 5 млн руб. ... бла-бла-бла';

S := StringReplace(S, 'млн', 'x10^6', [rfReplaceAll, frIgnoreCase,frWholeWordsOnly {я придумал этот флаг}]);
S := StringReplace(S, 'тыс', 'x10^3', [rfReplaceAll, frIgnoreCase,frWholeWordsOnly]);

S := CleanStr(S); // удаляет ненужные символы, оставляя только цифры, точку, запятую, x и ^.

// S = '5x10^6'

S := StringReplace(S, '.', DecimalSeparator, [rfReplaceAll]);
S := StringReplace(S, ',', DecimalSeparator, [rfReplaceAll]);

I := Calc(S);

// I = 5'000'000


Цитата
Т.е. вот это потом перевести в число?
Код
i := StrToInt('2,3 x 10 ^ 6')


Ну да, но это почти не отличается от твоего исходного варианта в тексте вопроса. Только что тут разбор выражения будет выполнять интерпретатор (привет, LiveBindings smile ), а у тебя - фиксированный код.

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

Должно работать, если в коде предусмотрены все сокращения.

А в целом тут не столько от алгоритма зависит, сколько от его шлифовки под реальные данные.

Автор: Akella 2.10.2011, 16:59
Цитата(CodeMonkey @  2.10.2011,  14:40 Найти цитируемый пост)
 а у тебя - фиксированный код.

У меня? А где у меня фиксированный код?

Автор: CodeMonkey 2.10.2011, 20:19
Я вот этот блок имел в виду:

Код
if pos('МЛН', AnsiUpperCase(m)) <> 0 then
begin
  ...
end;

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