Преобразование строки в число на Prolog

      Комментарии к записи Преобразование строки в число на Prolog отключены

В этой теме 2 ответа, 2 участника, последнее обновление  Васильев Владимир Сергеевич 1 год, 1 месяц назад.

  • Автор
    Сообщения
  • #2485

    questioner
    Участник

    Здравствуйте. Иногда нужно получить от пользователя число, но необходимо проверить правильно ли он его ввел. Кроме того, такая задача может возникать при считывании данных с файла.
    Сейчас мне нужно считать число, находящееся в начале “строки” и получить ее остаток. Число может быть как целым, так и дробным, т.е. допустимы варианты: “123”, “.123”, “54.67”. Пусть число будет всегда положительным (при необходимости знак я сам добавлю).

  • #2487

    Здравствуйте. Есть много вариантов решения задачи – на SWI Prolog есть почти готовые предикаты, с помощью которых задача решается легко и просто. В Visual Prolog функции ввода являются типизированными (например readint считывает целое число) и, если считать число не получается, – они завершаются неудачей без побочных эффектов (не изменяя состояния буфера ввода).

    Однако, такая задача реально может возникать если мы выполняем разбор данных в каком-то хитром формате. Я не уверен, что readint сработает правильно на строке типа “123.456-123”.

  • #2488

    Алгоритм разбора числа должен отделять от строки символы и проверять являются ли они цифрой, поэтому пригодится функция для проверки цифр:

    symbol_to_digit(DigitSymbol, Digit):-
      DigitSymbol >= 0'0, DigitSymbol =< 0'9,
      Digit is DigitSymbol - 0'0.

    Тут 0'9 – это код цифры 9, такой вариант работает в SWI Prolog и многих других диалектах. Если в вашем диалекте такой синтаксис не поддерживается – можно использовать ASCII коды символов – 48 и 58 соответственно.

    Наша функция должна принимать строку и возвращать первое число из нее и остаток строки.

    get_positive(String, Number, TailString):-
      symbol_to_digit(HeadDigit, _Digit), !,
      get_positive(integral, 0, String, Number, TailString).

    Мы вызываем вспомогательную функцию, при этом первый параметр integral означает, что сейчас вызываются правила считывания целой части, при этом начальное значение результата равно нулю.

    Вспомогательная функция должна:

    • переходить на обработку дробной части если встречен символ точка, результат при этом формируется как сумма целой и дробной частей.
    • считывать первую цифру числа и добавлять ее к накопленному результату, умноженному на 10;
    • возвращать накопленный результат, если первый символ не является цифрой:

    get_positive(integral, IntegralPart, [0'.|Tail], Number, TailString):-
      !, get_positive(fraction, 0, 10, Tail, FractionPart, TailString),
      Number is IntegralPart + FractionPart.
    get_positive(integral, IntegralPart, [HeadDigit|Tail], Number, TailString):-
      symbol_to_digit(HeadDigit, Digit), !,
      TailIntegralPart is IntegralPart*10 + Digit,
      get_positive(integral, TailIntegralPart, Tail, Number, TailString).
    get_positive(integral, Number, String, Number, String):-!.

    При обработке дробной части очередная цифра числа должна делиться на множитель, изначально равный 10, но увеличивающий в 10 раз при каждой итерации. Первый символ, отличный от цифры будет означать, что число кончилось и нужно вернуть накопленный результат:

    get_positive(fraction, FractionPart, Factor, [HeadDigit|Tail], Number, TailString):-
      symbol_to_digit(HeadDigit, Digit), !,
      TailFractionPart is FractionPart + Digit/Factor,
      TailFactor is Factor*10,
      get_positive(fraction, TailFractionPart, TailFactor, Tail, Number, TailString).
    get_positive(fraction, Number, _TailFactor, String, Number, String).

Для ответа в этой теме необходимо авторизоваться.