Форум «Всё о Паскале» _ Задачи _ Задача с использованием файла
Автор: -Студент- 13.12.2007 23:09
Вечер добрый форумчане. вощем задал препод на первый взгляд не очень сложную задачу , но он у меня вызывает ряд затруднений ... задание : Подсчитать кол-во слов содержащих хотябы одну букву "m"
вот текст программы , написал что мог
Код
program laba51; var f1:text; i:integer; s:string; begin assign(f1,'laba51.txt'); rewrite(f1); for i:=1 to 5 do begin readln(s); writeln(f1,s); end; close(f1); end.
program laba52; uses crt; var f1:text; i,k,l:integer; s:string; begin assign(f1,'laba51.txt'); reset(f1); k:=0; while not eof(f1) do for i:=1 to length(s) do begin readln(f1,s); if s[i]='m' then k:=k+1; i:=i+1; end; writeln ('kol-vo slov = ',k); close(f1); READKEY; end.
если не сложно , исправте пожалуйста ... очень мне поможите
в программе я не реализовал нахождеименно слова ... неполучается это сделать
Автор: -Студент- 15.12.2007 0:18
знающие люди , подскажите пожалуйста ... горю , на след. неделе начинается сессия , исправте алгоритм если вам это под силу
Автор: andriano 15.12.2007 0:46
У тебя проблема в этом фрагменте:
for i:=1 to length(s) do begin readln(f1,s); if s[i]='m' then k:=k+1; i:=i+1; end;
Смотри, ты организуешь цикл по всей длине строки ДО того, как ее прочитал. И чтение целой строки у тебя оказалось ВНУТРИ цикла по буквам строки. Оператор чтения нужно вынести из цикла - поставить его выше, чтобы к моменту начала цикла строка уже была прочитана. Далее, как только ты переставишь строчку, она окажеся вне begin...end, поэтому для выполнения всего цикла while понадобится еще парочка. Ну и переопределять переменную цикла внутри этого цикла недопустимо.
Автор: Айра 15.12.2007 0:58
for i:=1 to length(s) do begin readln(f1,s); //замени на read, иначе будет считываться только 1-й символ каждой строки if s[i]='m' then k:=k+1; i:=i+1; //так нельзя делать end;
А как такой вариант:
program laba52; uses crt; const simvol : set of char = [',','.',':',';','-', '!', '?', ' ']; //множество символов-разделителей слов var f1:text; k:integer; l: boolean; ch: char; begin l:=true; //true, если началось новое слово assign(f1,'laba51.txt'); {$I-} reset(f1); {$I+} if IoResult = 0 then //проверям, найден ли нужный файл begin k:=0; while not eof(f1) do begin read(f1,ch); //считываем посимвольно write(ch); //выводим для нагляности if ch in simvol then l:=true; //если ch символ-разделитель, то мы в новом слове if (ch='m') and l then //если ch нужный символ и слово новое, то... begin inc(k); l:=false; //теперь слово уже не новое, это значит, что если в слове несколько 'm', //то оно считается как одно слово с этой буквой, а не несколько end; end; writeln; writeln ('kol-vo slov = ',k); close(f1); end else writeln('файл не найден'); end.
если что непонятно, спрашивай
Автор: andriano 15.12.2007 1:11
Вообще-то s - это строка, так что проблем с этой строчкой кода быть не должно (кроме того, что она не в том месте)
readln(f1,s); //замени на read, иначе будет считываться только 1-й символ каждой строки
А вот эти две строки меня озадачивают:
if ch in simvol then l:=true; //если ch символ-разделитель, то мы в новом слове if (ch='m') and l then //если ch нужный символ и слово новое, то...
Строго говоря, первую строку можно записать в виде:
l := ch in simvol
А их вместе:
if (ch='m') and (ch in simvol) then //если ch нужный символ и слово новое, то...
Что эквивалентно
if FALSE then
т.к. один и тот же символ не может одновременно равняться m и быть разделителем. Таким образом весь этот блок можно выбросить, оставив только вывод нуля на экран.
Автор: Malice 15.12.2007 1:24
Цитата(andriano @ 14.12.2007 21:11)
А вот эти две строки меня озадачивают:
А что если назначение этой строки проявит себя на следующем витке цикла while ? Ее все равно можно сократить ? Коль уж вы взвалили на себя нелегкую миссию цензора, комментирущего код не вопрошающего, а отвечающего, то будьте добры производить наиполнейший анализ всего кода, чтобы от столь пространных умозаключений хотя бы не было вреда.
Автор: andriano 15.12.2007 1:53
Да, признаю, в анализе допустил ошибку. Тогда получается, что если текущий символ m, а предыдущий - разделитель, то учитываем. И эта возможность учесть у нас сохраняется до первого m, а затем утрачивается до нового разделителя. Да, получается, что приведенный код может работать. Но логика работы достаточно запутана. В исходной программе, вроде бы, предполагается, что текст содержит по одному слову на строке. Неплохо бы прояснить этот момент. Кстати, если учитывать разделители, то мне кажется, в их число необходимо внасти пробел и символ табуляции. А, возможно, даже все символы, явно не описанные как буквы. (опять же - неопределенность условия) Но не лучше ли поступить по следующему алгоритму: 1. Все разделители заменяются на пробелы. 2. Все двуойные пробелы заменяются на одинарные. 3. Строка режется на фрагменты по пробелам. 4. Каждый фрагмент проверяется на наличие искомого символа. ? Мне кажется, такой алгоритм более прозрачен и подходящ для учебных целей.
Автор: Айра 15.12.2007 2:21
Цитата
Но логика работы достаточно запутана.
Женская логика завораживает своей алогичностью (с)
Цитата
В исходной программе, вроде бы, предполагается, что текст содержит по одному слову на строке
В исходной программе, но в задании об этом ничего не сказано.. Будем ждать разъяснений автора?..
Цитата
в их число необходимо внасти пробел и символ табуляции
пробела там действительно нехватает.. внесла.. табуляцию внесла бы, если б знала как она выглядит))
Цитата
Мне кажется, такой алгоритм более прозрачен и подходящ для учебных целей.
Это твое ИМХО, если тебе так понятнее, то делай так, я же сделала как легче мне, тем более каких-то определенных условий по алгоритму в задании нет..
Автор: andriano 15.12.2007 2:54
Табуляция в Паскале обозначается #9. С точки зрения текстового файла интересна тем, что это СТАНДАРТНЫЙ разделитель для текстовых файлов экспортируемых/импортируемых Excell. То есть пример не учебный, а самый что ни на есть практический. ;)
Автор: -Студент- 15.12.2007 3:38
Предпологается , что в строке символов слов может быть сколько угодно ... и нужно считать именно те слова (а словом считается набор символов ограниченных с 2 - ух сторон пробелами) в которых есть хотябы 1 буква "m" т.е. слово "mama" будет считаться как 1 слово
Автор: andriano 15.12.2007 15:41
Цитата(-Студент- @ 14.12.2007 23:38)
словом считается набор символов ограниченных с 2 - ух сторон пробелами
Уточнение: правильно ли я понял, что в строке "мама мыла раму" содержится только одно слово "мыла", т.к. остальные ограничены пробелами лишь с одной стороны?
И еще:
Цитата
Предпологается , что в строке символов слов может быть сколько угодно ...
в Паскале строка не может содержать более 255 символов. Означает ли это, что программа должна уметь обрабатывать и более длинные строки (это возможно, но тогда весь инструментарий работы с такими строками придется писать самостоятельно)?
Автор: volvo 15.12.2007 16:14
Цитата
весь инструментарий работы с такими строками придется писать самостоятельно
Ты знаешь, если тебе делать особо нечего, можно и System.pas заново переписать, а так - весь инструментарий для работы со строками длиной до 64k находится в модуле Strings, можно его сразу использовать...
Автор: andriano 15.12.2007 17:13
В Паскале строк длиннее 255 символов НЕТ! Различные компиляторы Паскаля поддерживают разные РАСШИРЕНИЯ языка, несовместимые друг с другом. В ТМТ, напрмер, модуль strings допускает работу в 255-символьными строками, а также с оканчивающимися нулем стоками из одно- и двухбайтовых (unicode) символов. 64К-байтных строк там нет. А если бы и были, какая разница, если требуется обработка строк ЛЮБОЙ длины?
Автор: -Студент- 15.12.2007 18:41
2Andriano
Нет , в строке "мама мыла раму" будет 3 слова , слово с двумя и более "m" будет считаться как 1 слово , нужно подсчитать кол-во слов в которых есть хотябы 1 буква "m"
Автор: Айра 15.12.2007 19:11
Цитата
ограниченных с 2 - ух сторон пробелами
это предполагает, что других символов в строке нет?
А вообще, программка, которую я выкладывала выше, вроде работает нормально.. Разделяет на слова она, в принципе, так, как мы привыкли разделять (в плане знаков препинания и т.п.).. и считает тоже вроде верно.. Тебе в ней что-то непонятно, что-то неустраивает? Спрашивай. А то мы развели уже тут дискуссию по поводу действительно "не очень сложной задачи"
Автор: andriano 15.12.2007 19:23
Цитата(-Студент- @ 15.12.2007 14:41)
2Andriano
Нет , в строке "мама мыла раму" будет 3 слова , слово с двумя и более "m" будет считаться как 1 слово , нужно подсчитать кол-во слов в которых есть хотябы 1 буква "m"
Это явно противоречит тому, что ты писал выше:
Цитата
словом считается набор символов ограниченных с 2 - ух сторон пробелами
Так что за тобой третья попытка корректно сформулиовать условие задачи.
И, кстати, еще раз прошу уточнить насчет допустимой длины строки: если ограничение есть, целесообразнее читать файл как текст и воспользоваться стандартным набором процедур для работы со строками. Если ограничения нет, лучше читать файл как бинарный и решать задачу при помощи конечного автомата.
Автор: -Студент- 16.12.2007 0:41
ну задача для первого курса нечего сверхъестественного в ней быть недолжно , мне только непонятно что за переменная IoResult или это стандартная процедура ? и что за спец. символы {$I-} , такого мы ещё не изучали ... и ещё переменная "Inc" , за что он отвечает ? Объсните пожалуйста
2Andriano , допустимая длина строки стандартна , т.е. 255 символов.
Автор: Айра 16.12.2007 1:25
Цитата
что за переменная IoResult ... и что за спец. символы {$I-}
{$I} - директива компилятора, которая отлавливает ошибки ввода/вывода - если, например, файла, к которому ты обращаешься нет, то компилятор "поругается" и закроет программу. А {$I-} - отключиние этой проверки -> ошибка выскакивать не будет.. {$I+} - включение этой директивы. А вот функция IOResult возвращает результат последней операции ввода/вывода: 0 - если ошибки не было (файл нашелся) и какое-то положительное число (код ошибки), если операция ввода/вывода потерпела неудачу))
Т.е. для корректной обработки ошибок ввода/вывода я отключила стандартную проверку {$I} и использовала IoResult.
Цитата
переменная "Inc" , за что он отвечает
inc(x) - процедура, которая по умолчанию увеличивает значение аргумента x на 1, если ввести еще один параметр, например inc(x,5), то значение будет увеличиваться на 5.
Вроде объяснила, если еще что-то непонятно, спрашивай, попытаюсь расшифровать