Чтение из текстовых файлов : проблемы и тонкости

Книга адресована школьникам средних и старших классов, желающим испытать себя в «олимпийских схватках». Может быть полезна студентам-первокурсникам и преподавателям информатики.

Модераторы: Oleg_D, Модераторы

Re: Редактирование и вычитка книги

Сообщение bormant » 30.12.2012 19:03:13

Oleg_D писал(а):но мне надо учитывать текущий уровень подготовки читателя, здесь задачи подчинены целям соответствующих глав, а не сами по себе.
Как раз это-то вполне понятно.
Oleg_D писал(а):Думаю, что будет полезно чуть-чуть сказать в 31-й главе о функциях SeekEoln и SeekEof.
По крайней мере случай вполне подходящий, аналогичные вопросы приходится решать при построчной организации данных с неизвестным количеством элементов в строке. Без SeekEoln невозможно сказать, осталось ли что-либо в текущей строке, если вычитывать числовые значения при помощи Read, он перейдёт на следующую строку (где наткнётся на нечисловые данные с последующим Runtime Error (хотя ещё эту ситуацию можно обслуживать с {$i-} по IOResult/InOutRes)), а если вычитывать посимвольно до непробельного символа, этот самый непробельный символ без специальных знаний о внутренней структуре файловой переменной типа Text обратно в поток не вернуть, а приклеивать его к считанному Read числу отдельное удовольствие сродни ректальной тонзиллотомии.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Редактирование и вычитка книги

Сообщение Oleg_D » 31.12.2012 13:21:02

Добавил в 31-ю главу такой абзац:
---
Примечание. Лишние пробелы в конце строк (после оценок) тоже приведут к аварии программы, проследите, чтобы во входном файле их не было. Проблема концевых пробелов решается заменой вызовов функций Eoln и Eof соответственно вызовами функций SeekEoln и SeekEof. Эти функции дают TRUE, даже если между текущей позицией и концом строки (файла) располагаются несколько пустых символов: пробелов, табуляций или пустых строк (для SeekEof). Улучшить программу P_31_1 предлагаю вам самостоятельно.
---
Всех с наступающим Новым Годом! :)
Oleg_D
постоялец
 
Сообщения: 390
Зарегистрирован: 09.05.2011 11:28:36

Re: Редактирование и вычитка книги

Сообщение artischev » 08.01.2013 12:10:17

Oleg_D писал(а):Добавил в 31-ю главу такой абзац:
---
Примечание. Лишние пробелы в конце строк (после оценок) тоже приведут к аварии программы, проследите, чтобы во входном файле их не было. Проблема концевых пробелов решается заменой вызовов функций Eoln и Eof соответственно вызовами функций SeekEoln и SeekEof. Эти функции дают TRUE, даже если между текущей позицией и концом строки (файла) располагаются несколько пустых символов: пробелов, табуляций или пустых строк (для SeekEof). Улучшить программу P_31_1 предлагаю вам самостоятельно.
---

Спасибо, теперь будет совсем хорошо.
artischev
новенький
 
Сообщения: 12
Зарегистрирован: 27.12.2012 11:17:22

Re: Разбор примеров из книги

Сообщение Paster Fob » 04.02.2013 21:18:31

Парнишка писал(а):Ну и в конце, хочу спросить у знающих людей, если убрать if Cnt=CNumbers then break и позволить процедуре Read(F,N) читать последнюю пустую строку файла, почему она возвращает 0, там же ничего кроме управляющих кодов нет !?

Потому что это глюк FPC,если запустить на ТР ,то всё читается корректно.Об этом кстати уже ни раз говорилось в этом разделе.
Можно также воспользоваться функцией seekeof.
Аватара пользователя
Paster Fob
постоялец
 
Сообщения: 188
Зарегистрирован: 22.02.2011 21:53:36
Откуда: Новосибирск.

Re: Разбор примеров из книги

Сообщение xdsl » 05.02.2013 14:08:05

По поводу слишком короткого integer: в начале программы ставится {$mode objfpc}, благодаря чему integer становится longint.

Paster Fob писал(а):
Парнишка писал(а):Ну и в конце, хочу спросить у знающих людей, если убрать if Cnt=CNumbers then break и позволить процедуре Read(F,N) читать последнюю пустую строку файла, почему она возвращает 0, там же ничего кроме управляющих кодов нет !?

Потому что это глюк FPC,если запустить на ТР ,то всё читается корректно.Об этом кстати уже ни раз говорилось в этом разделе.
Можно также воспользоваться функцией seekeof.

Глюки тут ни при чем. Что-же еще должен возвратить read, читая число, когда между концом файла и текущей позицией есть только управляющий символ?
И турбо-паскаль (7.0) и фрипаскаль (2.6) возвращают 0:
Код: Выделить всё
var n:integer;
    f: text;
begin
  // создаем текстовый файл с символом(-ми) перевода строки
  Assign(F, 'num.txt');  rewrite(f);  writeln(f);  close(f);
  // читаем оттуда число
  Reset(F);  read(f,n);  Close(F);
// выводим, получаем 0, как в FPC так и TP
  writeln(n);
end.

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

Конкретно в этой программе от Cnt=CNumbers можно избавиться, например так:
Код: Выделить всё
...
while true do begin
     if Eoln(F) then Readln(F); { пропуск конца строки }
     if Eof(f) then break;
     Read(F, N);
     if N<min then min:=N;
     if N>max then max:=N;
     Sum:= Sum+N;
     Cnt:= Cnt+1;
  end;
...
xdsl
постоялец
 
Сообщения: 131
Зарегистрирован: 15.01.2009 13:49:03

Re: Разбор примеров из книги

Сообщение Vapaamies » 05.02.2013 21:00:50

xdsl писал(а):Что-же еще должен возвратить read, читая число, когда между концом файла и текущей позицией есть только управляющий символ?

Исключение. Пустая строка в данном случае -- нарушение соглашения по формату входных данных. Поначалу было подозрение, что значение 0 -- умолчательное значение глобальной переменной, но после проверки в Delphi 6 подтвердилось, что значение 0 в переменную вносит именно процедура чтения. Тогда глюк, ибо нелогично.

В справке Delphi по этому поводу написано буквально следующее:
With type integer or type real variables:
  • Read skips any blanks, tabs, or end-of-line markers preceding the numeric string.
  • If the numeric string does not conform to the expected format, an I/O error occurs; otherwise, the value is assigned to the variable.
  • The next Read starts with the blank, tab, or end-of-line marker that terminated the numeric string.

Почему пустая строка не считается за "does not conform to the expected format", не понимаю. Например, более современная StrToInt для пустой строки выдает исключение.

Если в примере выше вместо пустой строки в файл нагло записать строковое значение, исключение возникнет. Стало быть, исключения работают.
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 291
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Разбор примеров из книги

Сообщение xdsl » 06.02.2013 00:36:48

Vapaamies писал(а):
xdsl писал(а):Что-же еще должен возвратить read, читая число, когда между концом файла и текущей позицией есть только управляющий символ?

Исключение. Пустая строка в данном случае -- нарушение соглашения по формату входных данных. Поначалу было подозрение, что значение 0 -- умолчательное значение глобальной переменной, но после проверки в Delphi 6 подтвердилось, что значение 0 в переменную вносит именно процедура чтения. Тогда глюк, ибо нелогично.

Это не глюк, ибо документировано Борландом еще в ТП 5.0 или даже раньше. В главе 16 "Справочник по процедурам и функциям Турбо-Паскаля" читаем:
В случае переменной целого типа процедура Rеаd ожидает поступления последовательности символов, образующих число со знаком, согласно синтаксису, указанному в разделе "Числа" Главы 17 ("Символы и константы"). Любые пробелы, знаки табуляции или метки конца строки, предшествующие числовой строке, пропускаются. Считывание прекращается при обнаружении первого пробела, символа табуляции или метки конца строки, которые следуют за числовой строкой, или в том случае, если функция Еоf(f) принимает значение Тruе. Если числовая строка
не соответствует ожидаемому формату, то происходит ошибка ввода-вывода. В противном случае переменной присваивается
значение. Если функция Еоf(f) имела значение Тruе перед выполнением процедуры Rеаd, или функция Еоf(f) приняла значение Тruе при пропуске начальных пробелов, знаков табуляции или меток конца строки, то переменной присваивается нулевое значение. Следующая операция Rеаd начнется с пробела, символа табуляции или метки конца строки, которыми завершилась числовая строка.

В FPC и Delphi просто обеспечили обратную совместимость.

В документации FPC также говорится об этом прямым текстом (http://freepascal.org/docs-html/rtl/system/read.html)
If no data is available, empty values are returned (0 for ordinal values, empty strings for string values)
xdsl
постоялец
 
Сообщения: 131
Зарегистрирован: 15.01.2009 13:49:03

Re: Чтение из текстовых файлов : проблемы и тонкости

Сообщение Oleg_D » 06.02.2013 10:12:14

Проверил следующую программу в BP и Delphi на файле, содержащем лишь несколько пустых строк.
Код: Выделить всё
var F: Text;
    N: integer;
begin
  Assign(F,'Integer.txt'); Reset(F);
  while not Eof(F) do begin
    Readln(F, N);
    Writeln(N)
  end;
  Close(F);
  Write('ok'); Readln;
end.

Действительно, выдаёт один ноль. Не очень логично, но это так.
Вероятно, самое простое и универсальное решение -- при чтении чисел вызывать SeekEoln() и SeekEof ().
Oleg_D
постоялец
 
Сообщения: 390
Зарегистрирован: 09.05.2011 11:28:36

Re: Чтение из текстовых файлов : проблемы и тонкости

Сообщение Vapaamies » 07.02.2013 00:16:17

Oleg_D писал(а):Вероятно, самое простое и универсальное решение -- при чтении чисел вызывать SeekEoln() и SeekEof ().

Вот к чему приводит неверие Вирта в исключения.
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 291
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Чтение из текстовых файлов : проблемы и тонкости

Сообщение xdsl » 07.02.2013 07:58:09

Vapaamies писал(а):
Oleg_D писал(а):Вероятно, самое простое и универсальное решение -- при чтении чисел вызывать SeekEoln() и SeekEof ().

Вот к чему приводит неверие Вирта в исключения.

Причем тут Вирт? Все претензии к Борланду. Да и то, какие могут быть претензии, если фича документирована?
xdsl
постоялец
 
Сообщения: 131
Зарегистрирован: 15.01.2009 13:49:03

Пред.

Вернуться в Книга "Песни о Паскале"

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru