Spec-Zone.ru › OCaml

Модуль 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.

  • С момента 3.10
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 в случае неудачи сканирования.

  • С момента 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

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

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

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

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

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

© 1995-2024 INRIA.
https://ocaml.org/manual/5.2/api/Scanf.html

Spec-Zone.ru

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