Spec-Zone.ru › OCaml 5.0

Модуль Scanf

module Scanf: sig .. end

Функции форматированного ввода.

  • Предупреждение unsynchronized_access. Несинхронизированные обращения к Scanning.in_channel являются программно ошибочными.

Введение

Функциональный ввод с использованием строк формата

Модуль Scanf предоставляет функции форматированного ввода или сканеры.

Функции форматированного ввода могут считывать данные из любого типа ввода, включая строки, файлы или что угодно, что может возвращать символы. Более общий источник символов называется каналом форматированного ввода (или буфером сканирования) и имеет тип Scanf.Scanning.in_channel. Более общая функция форматированного ввода считывает данные из любого буфера сканирования и называется bscanf.

В общем случае, функции форматированного ввода имеют 3 аргумента:

  • первый аргумент — источник символов для ввода,
  • второй аргумент — строка формата, определяющая значения для чтения,
  • третий аргумент — функция-приемник, которая применяется к прочитанным значениям.

Следовательно, типичный вызов функции форматированного ввода Scanf.bscanf выглядит так: bscanf ic fmt f, где:

  • ic — источник символов (обычно канал форматированного ввода типа Scanf.Scanning.in_channel),
  • fmt — строка формата (та же строка формата, что и используемая для вывода данных с модулем Printf или Format),
  • f — функция, имеющая столько аргументов, сколько значений должно быть прочитано из ввода согласно fmt.

Простой пример

Как указано выше, выражение bscanf ic "%d" f считывает целое десятичное число n из источника символов ic и возвращает f n.

Например,

  • если мы используем stdin в качестве источника символов (Scanf.Scanning.stdin — предопределенный канал форматированного ввода, который считывает данные со стандартного ввода),
  • если мы определим функцию-приемник f как let f x = x + 1,

тогда bscanf Scanning.stdin "%d" f считывает целое число n со стандартного ввода и возвращает f n (то есть n + 1). Таким образом, если мы вычислим bscanf stdin "%d" f, а затем введём 41 с клавиатуры, результат будет 42.

Форматированный ввод как функциональная функция

Функциональность OCaml для сканирования напоминает соответствующую функцию C. Однако она также значительно отличается, проще и при этом мощнее: функции форматированного ввода являются высшими функциональными функциями, а механизм передачи параметров — это просто обычное применение функции, а не механизм назначения переменных, характерный для форматированного ввода в императивных языках; строки формата OCaml также содержат полезные дополнения для лёгкого определения сложных токенов; как и ожидается в функциональном языке программирования, функции форматированного ввода также поддерживают полиморфизм, в частности, произвольные взаимодействия с полиморфными сканерами, определенными пользователем. Кроме того, функциональность форматированного ввода OCaml полностью проверяется во время компиляции.

Несинхронизированные обращения

Несинхронизированные обращения к Scanf.Scanning.in_channel могут привести к недопустимому состоянию Scanf.Scanning.in_channel. Таким образом, одновременные обращения к Scanf.Scanning.in_channel должны быть синхронизированы (например, с помощью Mutex.t).

Канал форматированного ввода

module Scanning: sig .. end

Тип функций форматированного ввода

type ('a, 'b, 'c, 'd) scanner = ('a, Scanning.in_channel, 'b, 'c, 'a -> 'd, 'd) format6 -> 'c 

Тип сканеров форматированного ввода: ('a, 'b, 'c, 'd) scanner — это тип функции форматированного ввода, которая считывает данные из канала форматированного ввода в соответствии со строкой формата; точнее, если scan — некоторая функция форматированного ввода, то scan
    ic fmt f
применяет f ко всем аргументам, указанным в строке формата fmt, когда scan прочитал эти аргументы из канала форматированного ввода Scanf.Scanning.in_channel ic.

Например, функция Scanf.scanf ниже имеет тип ('a, 'b, 'c, 'd) scanner, так как это функция форматированного ввода, которая считывает данные из Scanf.Scanning.stdin: scanf fmt f применяет f к аргументам, указанным в fmt, считывая эти аргументы из stdin, как ожидается.

Если в формате fmt есть какие-либо указания %r, соответствующие функции форматированного ввода должны быть предоставлены до функции-приемника f. Например, если read_elem — это функция ввода для значений типа t, то bscanf ic "%r;" read_elem f считывает значение v типа t, за которым следует символ ';' и возвращает f v.

  • Since 3.10.0
type ('a, 'b, 'c, 'd) scanner_opt = ('a, Scanning.in_channel, 'b, 'c, 'a -> 'd option, 'd) format6 ->       'c 
exception Scan_failure of string

Когда ввод не может быть прочитан в соответствии со спецификацией строки формата, функции форматированного ввода обычно генерируют исключение Scan_failure.

Общая функция форматированного ввода

val bscanf : Scanning.in_channel -> ('a, 'b, 'c, 'd) scanner

bscanf ic fmt r1 ... rN f считывает символы из канала форматированного ввода Scanf.Scanning.in_channel ic и преобразует их в значения в соответствии со строкой формата fmt. На заключительном этапе функция-приемник f применяется к прочитанным значениям и возвращает результат вызова bscanf.

Например, если f — это функция fun s i -> i + 1, тогда Scanf.sscanf "x = 1" "%s = %i" f возвращает 2.

Аргументы r1 до rN — это пользовательские функции ввода, которые считывают аргумент, соответствующий преобразованиям %r, указанным в строке формата.

val bscanf_opt : Scanning.in_channel -> ('a, 'b, 'c, 'd) scanner_opt

Аналогично Scanf.bscanf, но возвращает None в случае ошибки сканирования.

  • Since 5.0

Описание строки формата

Строка формата — это строка символов, которая содержит три типа объектов:

  • простые символы, которые просто сопоставляются с символами ввода (с особым случаем для пробела и символа новой строки, см. Символ пробела в строках формата),
  • спецификации преобразования, каждая из которых вызывает чтение и преобразование одного аргумента для функции f (см. Спецификации преобразования в строках формата),
  • указания сканирования для определения границ токенов (см. Указания сканирования в строках формата).

Символ пробела в строках формата

Как упоминалось выше, простой символ в строке формата просто сопоставляется с следующим символом ввода; однако два символа являются особыми исключениями из этого правила: символ пробела (' ' или ASCII-код 32) и символ новой строки ('\n' или ASCII-код 10). Пробел не соответствует одному символу пробела, а любому количеству «пробелов» во вводе. Точнее, пробел внутри строки формата соответствует любому количеству символов табуляции, пробела, новой строки и возврата каретки. Аналогично, символ новой строки в строке формата соответствует либо одной новой строке, либо возврату каретки, за которым следует новая строка.

Сопоставляя любое количество пробелов, пробел в строке формата также соответствует нулю пробелов; следовательно, вызов bscanf ib
    "Price = %d $" (fun p -> p)
успешно выполняется и возвращает 1 при чтении ввода с различными пробелами, такими как Price = 1 $, Price  =  1    $, или даже Price=1$.

Спецификации преобразования в строках формата

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

Символы преобразования и их значения:

  • d: считывает необязательно со знаком десятичное целое число (0-9+).
  • i: считывает необязательно со знаком целое число (обычные соглашения ввода для десятичных (0-9+), шестнадцатеричных (0x[0-9a-f]+ и 0X[0-9A-F]+), восьмеричных (0o[0-7]+) и двоичных (0b[0-1]+) представлений понимаются).
  • u: считывает целое десятичное число без знака.
  • x или X: считывает шестнадцатеричное целое число без знака ([0-9a-fA-F]+).
  • o: считывает восьмеричное целое число без знака ([0-7]+).
  • s: считывает строковый аргумент, который расширяется по возможности до тех пор, пока не выполнится следующее условие:
    • был найден пробел (см. Пробельный символ в строках формата),
    • встречено указание сканирования (см. сканирование Указания сканирования в строках формата),
    • достигнут конец ввода.
    Следовательно, это преобразование всегда выполняется успешно: оно возвращает пустую строку, если условие завершения выполняется при начале сканирования.
  • S: считывает строковый аргумент с разделителями (разделители и специальные символы экранирования следуют лексическим соглашениям OCaml).
  • c: считывает одиночный символ. Чтобы проверить текущий символ ввода без его чтения, укажите ширину поля равную нулю, т.е. используйте спецификацию %0c. Вызовите Invalid_argument, если спецификация ширины поля больше 1.
  • C: считывает одиночный символ с разделителями (разделители и специальные экранированные символы следуют лексическим соглашениям OCaml).
  • f, e, E, g, G: считывает необязательно со знаком число с плавающей точкой в десятичной записи в формате dddd.ddd
          e/E+-dd
    .
  • h, H: считывает необязательно со знаком число с плавающей точкой в шестнадцатеричной записи.
  • F: считывает число с плавающей точкой согласно лексическим соглашениям OCaml (следовательно, десятичная точка обязательна, если часть порядка не указана).
  • B: считывает булевый аргумент (true или false).
  • b: считывает булевый аргумент (для обратной совместимости; не использовать в новых программах).
  • ld, li, lu, lx, lX, lo: считывает int32 аргумент в формате, указанном второй буквой для обычных целых чисел.
  • nd, ni, nu, nx, nX, no: считывает nativeint аргумент в формате, указанном второй буквой для обычных целых чисел.
  • Ld, Li, Lu, Lx, LX, Lo: считывает int64 аргумент в формате, указанном второй буквой для обычных целых чисел.
  • [ range ]: считывает символы, соответствующие одному из символов, упомянутых в диапазоне символов range (или не упомянутых в нем, если диапазон начинается с ^). Считывает string , которая может быть пустой, если следующий символ ввода не соответствует диапазону. Множество символов от c1 до c2 (включительно) обозначается c1-c2. Следовательно, %[0-9] возвращает строку, представляющую десятичное число, или пустую строку, если десятичная цифра не найдена; аналогично, %[0-9a-f] возвращает строку шестнадцатеричных цифр. Если закрывающая скобка появляется в диапазоне, она должна появляться как первый символ диапазона (или сразу после ^ в случае отрицания диапазона); следовательно []] соответствует символу ], а [^]] соответствует любому символу, который не является ]. Используйте %% и %@ для включения % или @ в диапазон.
  • r: пользовательское чтение. Принимает следующую ri форматированную функцию ввода и применяет ее к буферу сканирования ib для чтения следующего аргумента. Функция ввода ri должна, следовательно, иметь тип Scanning.in_channel -> 'a, а считанный аргумент имеет тип 'a.
  • { fmt %}: считывает строковый аргумент формата. Прочитанная строка формата должна иметь тот же тип, что и спецификация строки формата fmt. Например, "%{ %i %}" считывает любую строку формата, которая может считывать значение типа int; следовательно, если s - строка "fmt:\"number is %u\"", то Scanf.sscanf s "fmt: %{%i%}" успешно выполняется и возвращает строку формата "number is %u".
  • ( fmt %): замена подформата сканирования. Считывает строку формата rf в вводе, затем продолжает сканирование с rf вместо сканирования с fmt. Строка формата rf должна иметь тот же тип, что и спецификация строки формата fmt , которую она заменяет. Например, "%( %i %)" считывает любую строку формата, которая может считывать значение типа int. Преобразование возвращает прочитанную строку формата rf, а затем значение, считанное с помощью rf. Таким образом, если s - строка "\"%4d\"1234.00", то Scanf.sscanf s "%(%i%)" (fun fmt i -> fmt, i) вычисляется как ("%4d", 1234). Это поведение не является просто заменой формата, поскольку преобразование возвращает прочитанную строку формата как дополнительный аргумент. Если вам нужна чистая замена формата, используйте специальный флаг _ для отбрасывания лишнего аргумента: преобразование %_( fmt %) считывает строку формата rf и затем ведет себя так же, как строка формата rf. Таким образом, если s - строка "\"%4d\"1234.00", то Scanf.sscanf s "%_(%i%)" просто эквивалентно Scanf.sscanf "1234.00" "%4d".
  • l: возвращает количество прочитанных строк до сих пор.
  • n: возвращает количество прочитанных символов до сих пор.
  • N или L: возвращает количество прочитанных токенов до сих пор.
  • !: соответствует условию конца ввода.
  • %: соответствует одному символу % в вводе.
  • @: соответствует одному символу @ в вводе.
  • ,: ничего не делает.

После символа % , который вводит преобразование, может быть специальный флаг _: последующее преобразование выполняется как обычно, но результирующее значение отбрасывается. Например, если f - функция fun i -> i + 1, а s - строка "x = 1", то Scanf.sscanf s "%_s = %i" f возвращает 2.

Ширина поля состоит из необязательной целочисленной литеральной величины, указывающей максимальную ширину токена для чтения. Например, %6d считывает целое число, имеющее не более 6 десятичных цифр; %4f считывает число с плавающей точкой с не более чем 4 символами; а %8[\000-\255] возвращает следующие 8 символов (или все доступные символы, если доступно меньше 8 символов в вводе).

Примечания:

  • как упоминалось выше, преобразование %s всегда выполняется успешно, даже если в вводе нет ничего для чтения: в этом случае оно просто возвращает "".
  • кроме соответствующих цифр, символы '_' могут появляться внутри чисел (это напоминает обычные лексические соглашения OCaml). Если требуется более строгое сканирование, используйте средство преобразования диапазона вместо преобразований чисел.
  • средство scanf не предназначено для сложного лексического анализа и разбора. Если оно кажется недостаточно выразительным для ваших потребностей, существуют несколько альтернатив: регулярные выражения (модуль Str), парсеры потоков, ocamllex-сгенерированные лекеры, ocamlyacc-сгенерированные парсеры.

Указания сканирования в строках формата

Указания сканирования появляются сразу после преобразований строк %s и %[ range ] для определения конца токена. Указание сканирования вводится символом @ , за которым следует некоторый обычный символ c. Это означает, что строковый токен должен заканчиваться непосредственно перед следующим совпадающим символом c (который пропускается). Если символ c не встречается, строковый токен расширяется по возможности. Например, "%s@\t" считывает строку до следующего символа табуляции или до конца ввода. Если символ @ появляется в другом месте в строке формата, он обрабатывается как обычный символ.

Примечание:

  • Как обычно в строках формата, символы % и @ должны быть экранированы с помощью %% и %@; это правило по-прежнему действует в спецификациях диапазонов и указаниях сканирования. Например, формат "%s@%%" считывает строку до следующего символа %, а формат "%s@%@" считывает строку до следующего символа @.
  • Указания сканирования вносят небольшие различия в синтаксисе строк формата Scanf по сравнению с теми, которые используются для модуля Printf. Однако, указания сканирования аналогичны тем, которые используются в модуле Format; следовательно, при создании форматированного текста для сканирования с помощью Scanf.bscanf, разумно использовать функции вывода из модуля Format (или, если вам нужно использовать функции из Printf, избавьтесь или тщательно проверьте строки формата, содержащие символы '@').

Исключения во время сканирования

Сканеры могут вызывать следующие исключения, когда входные данные не могут быть прочитаны в соответствии со строкой формата:

  • Вызвать Scanf.Scan_failure, если входные данные не соответствуют формату.
  • Вызвать Failure , если преобразование в число невозможно.
  • Вызовите End_of_file в случае, если конец входных данных достигнут, а для чтения текущего спецификатора преобразования требуется ещё несколько символов.
  • Вызовите Invalid_argument в случае, если строка формата неверна.

Примечание:

  • вследствие этого, сканирование %s преобразования никогда не вызывает исключения End_of_file: если достигнут конец входных данных, преобразование завершается успешно и просто возвращает прочитанные до этого символы, или "" в случае, если не было прочитано ни одного символа.

Специализированные функции форматированного ввода

val sscanf : string -> ('a, 'b, 'c, 'd) scanner

То же, что и Scanf.bscanf, но читает из заданной строки.

val sscanf_opt : string -> ('a, 'b, 'c, 'd) scanner_opt

То же, что и Scanf.sscanf, но возвращает None в случае неудачного сканирования.

  • Since 5.0
val scanf : ('a, 'b, 'c, 'd) scanner

То же, что и Scanf.bscanf, но читает из предопределённого форматированного канала ввода Scanf.Scanning.stdin, который подключён к stdin.

val scanf_opt : ('a, 'b, 'c, 'd) scanner_opt

То же, что и Scanf.scanf, но возвращает None в случае неудачного сканирования.

  • Since 5.0
val kscanf : Scanning.in_channel ->       (Scanning.in_channel -> exn -> 'd) -> ('a, 'b, 'c, 'd) scanner

То же, что и Scanf.bscanf, но принимает дополнительный аргумент функции ef, который вызывается в случае ошибки: если процесс сканирования или какое-либо преобразование завершается неудачей, функция сканирования прерывается и вызывает функцию обработки ошибок ef с форматированным каналом ввода и исключением, прервавшим процесс сканирования, в качестве аргументов.

val ksscanf : string ->       (Scanning.in_channel -> exn -> 'd) -> ('a, 'b, 'c, 'd) scanner

То же, что и Scanf.kscanf, но читает из заданной строки.

  • Since 4.02.0

Чтение строк формата из входных данных

val bscanf_format : Scanning.in_channel ->       ('a, 'b, 'c, 'd, 'e, 'f) format6 ->       (('a, 'b, 'c, 'd, 'e, 'f) format6 -> 'g) -> 'g

bscanf_format ic fmt f читает маркер строки формата из форматированного канала ввода ic, согласно заданной строке формата fmt, и применяет f к полученному значению строки формата.

  • Since 3.09.0
  • Вызывает Scan_failure если значение прочитанной строки формата не имеет того же типа, что и fmt.
val sscanf_format : string ->       ('a, 'b, 'c, 'd, 'e, 'f) format6 ->       (('a, 'b, 'c, 'd, 'e, 'f) format6 -> 'g) -> 'g

То же, что и Scanf.bscanf_format, но читает из заданной строки.

  • Since 3.09.0
val format_from_string : string ->       ('a, 'b, 'c, 'd, 'e, 'f) format6 ->       ('a, 'b, 'c, 'd, 'e, 'f) format6

format_from_string s fmt преобразует строковый аргумент в строку формата согласно заданной строке формата fmt.

  • Since 3.10.0
  • Вызывает Scan_failure если s, рассматриваемая как строка формата, не имеет того же типа, что и fmt.
val unescaped : string -> string

unescaped s возвращает копию s с последовательностями экранирования (согласно лексическим соглашениям OCaml) заменёнными соответствующими специальными символами. Более точно, Scanf.unescaped обладает следующим свойством: для всех строк s, Scanf.unescaped (String.escaped s) = s.

Всегда возвращает копию аргумента, даже если в аргументе нет последовательностей экранирования.

  • Since 4.00.0
  • Вызывает Scan_failure если s не правильно экранирована (т.е. s имеет неверные последовательности экранирования или специальные символы, которые не правильно экранированы). Например, Scanf.unescaped "\"" завершится ошибкой.

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/libref/Scanf.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API