Помощь - Поиск - Пользователи - Календарь
Полная версия: Прошу помочь с исправлением ошибок в программе
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
student___
Здравствуйте. Дана задача : Для каждого символа заданного текста указать его относительную частоту появления в тексте. Построить соответствующую диаграмму. Сообщение об одном символе должно печататься не более одного раза. Вот мой черновик. программа читает текст из файла, который может состоять из любого количества символов(английские , русские буквы, всевозможные знаки препинания и все это в несколько строк), выводить нужно только символы-буквы. всё шло прекрасно до того момента как текст состоял из двух-трёх строк, но если читать ,к примеру, полноценное стихотворение, то начинаются ошибки(выводит несколько раз сообщение об одинаковых символах, некоторые буквы не выводит вовсе, неправильно считает) и как мне уже подсказали формула по которой считается относительная частота не верна(.до диаграммы дело не доходит так понимаю, что смысла нет за неё браться пока происходят вот такие косяки.. Прошу посмотреть программу и помочь с выявлением ошибок

 
Program chast;
uses crt;
var t: text;
s: string;
a: array [0..255] of integer;
k, b, i, max:integer;
BEGIN clrscr;
k:=0;
assign(t,'int.pas');
reset(t);
while not (eof(t)) do
begin

readln(t,s);
for i:=1 to length(s) do
begin
inc(k);
case ord(s[i]) of 97..122,224..255:inc(a[ord(s[i])]);
65..90,128..159:begin
s[i]:=chr(ord(s[i])+32);
inc(a[ord(s[i])]);
end;
end;
end;

writeln('Относительная частота повторений символов в тексте');
writeln;
max:=0;
for i:=32 to 255 do
if a[i]<>0 then begin
writeln(chr(i),'-','частота',(a[i]/100*k): 3 :2,'',' % ',
' встречается в тексте ',a[i],' раз(а)');
if a[i]>max then begin
max:=a[i] ;
b:=i
end;
end;
end;
writeln;
writeln;
writeln('всего символов - ',k, ' больше всего встречается-',chr(b),' ', max,' раз(а)');
close(t);
readln;
end.
Федосеев Павел
Я так понимаю, что на каком-то форуме ты уже побывал.

Если выполняешь самостоятельно, то разберёшься.

1. Отформатируй текст программы. Станет видна основная ошибка - результат выводится после обработки каждой строки, а не по окончанию файла.

2. Действительно, странно как-то ты считаешь относительную частоту. Посчитай появление каждого символа из требуемого диапазона в тексте. Потом и выводи результат.
Код
  if s[i] in ['a'..'z', 'A'..'Z', 'а'..'я', 'А'..'Я'] then {здесь не вполне корректно задан русский алфавит - подправишь сам}
    inc(a[ord(s[i])]);
student___
[quote name='Федосеев Павел' date='14.04.2013 18:52' post='161990']
Я так понимаю, что на каком-то форуме ты уже побывал.

Если выполняешь самостоятельно, то разберёшься.

1. Отформатируй текст программы. Станет видна основная ошибка - результат выводится после обработки каждой строки, а не по окончанию файла.

2. Действительно, странно как-то ты считаешь относительную частоту. Посчитай появление каждого символа из требуемого диапазона в тексте. Потом и выводи результат.
Код
  if s[i] in ['a'..'z', 'A'..'Z', 'а'..'я', 'А'..'Я'] then {здесь не вполне корректно задан русский алфавит - подправишь сам}
    inc(a[ord(s[i])]);

[/quote]

интересная штука получилось, читая Ваш совет, а именно
Код
  if s[i] in ['a'..'z', 'A'..'Z', 'а'..'я', 'А'..'Я'] then
    inc(a[ord(s[i])]);

[/quote]
думала сначала сделать так
Код
  if s[i] in ['a'..'z'] then inc(a[ord(s[i])]);
else                       {разделила потому что большие буквы нужно преобразовать в маленькие}
if s[i] in ['A'..'Z'] then begin
                                s[i]:=chr(ord(s[i])+32);
                                inc(a[ord(s[i])]);
                                 end;

либо я чего то не допонимаю либо я все-таки чего то недопонимаю, так как если разбивать , то у меня не считает "а", так же как и в моем изначальном варианте а малую программа не считала вообще. НО если пишу
Код
  if s[i] in ['a'..'z'] then
    inc(a[ord(s[i])]);
, то мало того что все считает, она даже большие считает и на экран выдает все в виде малых букв.( это по поводу латинских букв, с русскими пока не делаю)
это конечно великолепно что так получается,НО я не понимаю почему она считает и большие и малые, если я большие даже не пишу в список?
Федосеев Павел
Да-а-а, что-то я запамятовал о различии кодов прописных и строчных букв.
Тогда, наверное нужно сделать
Код

  MyABC:=['a'..'z', 'A'..'Z', 'а'..'я', 'А'..'Я'];
...................
      if s[i] in MyABC then
        inc(a[ord( MyLoCase(s[i]) )]);

А ранее определить процедуру MyLoCase(c: char): char, которая будет переводить символы в "нижний" регистр. Для латинских символов она уже есть стандартная, а для русских придётся самостоятельно добавить
Код
function MyLoCase(c: char): char;
begin
  case c of
    'a'..'z', 'A'..'Z': MyLoCase:=locase(c);
    'а'..'я', 'А'..'Я': MyLoCase:=........ что-то своё
  else
    MyLoCase:=c;
end;

И ещё, я не совсем понял что там считается не так. Если можно покажи код, тестовый файл и ожидаемый результат. Смею предположить, что перед использованием массива a его нужно обнулять.
student___
мне кажется так будет проще
Код
for i := 1 to length (s) do begin  
            s[i] := lowercase(s[i]);  
            inc (a[ord (s[i])]);      
          end;

или нет?
Федосеев Павел
Прога твоя - решай сама. Но твой вариант гораздо нагляднее.
student___
такой вопрос. Чтобы подсчитать относительную частоту появления какого-то символа, нужно посчитать кол-во символов (в моем случае исключая пробелы и знаки препинания) и разделить кол-во появлений данного символа на общее число символов. так? но вот вопрос на общее число символов вообще или на общее кол-во встречающихся символов?(т.е. считать что буквы повторяются или раздилить на кол-во используемых символов?)
Федосеев Павел
На общее количество символов в тексте. Но символов не всех, а только из интересующего тебя диапазона, например, 'a'..'z'.
student___
не могу понять как это реализовать. все символу подсчитать могу, а как исключить пробелы и знаки препинания?
прокручиваю вариант использования pos и delete...хотя это совсем не лучший вариант

Добавлено через 2 мин.
или if s[i] in ['a'..'z'] then inc(h){в итоге h покажет сколько всего?}?

Добавлено через 3 мин.
вроде работает . как на Ваш взгляд есть лучше вариант?

Добавлено через 15 мин.
вот на данный момент так, проверте пожалуйста
Код
uses  
CRT;
var  
t: text;
s: string;  
a: array [0..255] of integer;  
h, k, i:integer;  
  BEGIN      clrscr;  
assign (t, 'int.pas');  
reset  (t);        
while not (eof (t)) do BEGIN
readln (t, s);  
inc(k); {строки}          
for  i := 1 to length (s) do begin  
inc(k);{сколько в строке}  
s[i] := lowercase(s[i]);  
inc (a[ord (s[i])]);    
if s[i] in ['a'..'z'] then inc(h);{общее кол-во букв}  
        END;
end;      
for i := 65 to 255 do  
if  (a[i] <> 0)   then            
writeln (chr(i), ' - ','частота*-',( a[i]/h):3:3,', встречается раз -',a[i],'   ','всего символов(букв)',h);  
close (t);  
readln;
END.


Добавлено через 1 мин.
правильно ли подсчитана частота?
Федосеев Павел
Добавь в начале программы обнуление элементов массива a - это ОБЯЗАТЕЛЬНО.
Инкремент inc (a[ord (s[i])]) выполняй после проверки вхождения символа в ['a'..'z']

Отформатируй код.Автоматические форматтеры

Улучшить код, конечно, можно. Но на данном этапе обучения, я боюсь тебя запутать.
Например,
- интересующие символы в if использовать в виде константы if s[i] in MyABC then
- убрать неиспользуемые модуль CRT, переменную k
- закрывать файл сразу после использования - после цикла while
- добавить обработку кириллицы применительно к конкретной кодовой странице (CP866 или CP1251)
student___
мне еще диаграмму к ней писать..

Добавлено через 1 мин.
объясните пожалуйста зачем обнулять эл-ты массива?

Добавлено через 9 мин.
сделоть то не трудно ,но хочется понимать
Федосеев Павел
Чтобы уберечься от неожиданных результатов при заполнении простаранства памяти случайным "мусором".
student___
и на счет MyABC. первый раз вижу, не разу этого не встречала, понятия не имею что это и преподаватели такого не объясняли поэтому думаю лучше обойтись без этого , дабы избежать лишних объяснений

Добавлено через 4 мин.
спасибо, Вы мне очень помогли. но хотелось бы попросить помощи в вопросе про диаграмму. необходимо вывести соответствующую диаграмму. с графом то работала, но вот опять таки как это реализовать основываясь на моих данных. предполагаю придется делать процедуру. подскажите хотябы с алгоритмом, как быть?

Добавлено через 19 мин.
и перед этим. зачем закрывать файл сразу после использования - после цикла while? какая разница?
Федосеев Павел
Файл закрывается потому, что завершился кусок кода обработки данных. Далее идёт кусок визуализации результатов обработки.

MyABC и условие в if s[i] in ['a'..'z'] - это работа с типом МНОЖЕСТВО - set of char.

Я почти не работал с graph, только предполагаю.
Визуализация в графическом режиме.
1. Масштабирование по X и по Y
2. Рисование прямоугольников с заполнением.

Масштабирование.
1. По X
Пусть обрабатывались N=26 символов от 'a' до 'z'.
Тогда ширина каждого прямоугольника будет равна
dX:=(GetMaxX+1) div N
Но лучше рисовать диаграмму немного отступив от края экрана, например 5% слева и 5% справа. Таким образом, остаётся всего лишь 90% ширины и получим
dXshift:=( (GetMaxX+1)*5 ) div 100 {отступ от края экрана 5%}
dX:=( (GetMaxX+1) - dXshift - dXshift) div N {ширина каждого прямоугольника}
2. По Y
Среди значений массива (в нужном диапазоне символов от 'a' до 'z') ищется максимальный - Amax.
Аналогично находим высоту максимального прямоугольника
dYshift:=( (GetMaxY+1)*5 ) div 100 {отступ от края экрана 5%}
dYmax:=(GetMaxX+1) - dYshift - dYshift
А высоты каждого рисуемого прямоугольника будут находиться
dY:=(a[i]*dYmax) div Amax

Рисование прямоугольников (псевдокод) с учётом что X возрастает слева направо, а Y сверху вниз
Код

  for i:=ord('a') to ord('z') do
  begin
    dY:=(a[i]*dYmax) div Amax
    Xstart:=dXshift+dX*( i-ord('a') )
    Ystart:=(GetMaxY+1)-dYshift
    Xstop:=Xstart+dX
    Ystop:=Ystart-dY
    прямоугольник(Xstart, Ystart, Xstop, Ystop)  {кажется, bar или rectangle}
  end;

Может быть, при вызове bar нужно будет поменять местами Ystart и Ystop, нужно установить цвета, стили заполнения. Я просто не знаю. Нужно пробовать.

Наверняка, в интернете вообще и на форуме в частности есть примеры построения диаграмм.

P.S. Препод от нас требовал не графическую диаграмму, а горизонтальную в текстовом режиме символами '*'.
Код

  dYmax:=80
  for i:=ord('a') to ord('z') do
  begin
    dY:=(a[i]*dYmax) div Amax
    for Y:=1 to dY do
      write('*');
    writeln;
  end;


В понедельник я уезжаю, больше помочь не смогу...
student___
Спасибо Вам большое. буду пробовать
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.