Помощь - Поиск - Пользователи - Календарь
Полная версия: Кодирование длин серий . Текстовый файл.
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
lopata
Помогите пожалуйста разобраться как делать.

Кодирование длин серий (Run-length encoding, RLE) - простая техника сжатия,при которой каждая последовательность знаков, которые состоят более чем из 2 одинаквых знаков, кодируется по первому знаку и длине последовательности.
Реализуйте простой вариант этого способа в форме программы фильта, которая кодирует и снова декодирует текстовые файлы,в которых содержатся только строчные и прописные буквы , знаки препинания и пробелы (но не цифры).Ваша программа должна предлогать следующие возможности вызова из камандной строки (метасимболы[...] и ...|... стоят для опций или альтернатив):
RLE [ -c | -d ] [inFile] [outFile]

Значение параметров:
-c входной файл нужно кодировать (значение по умолчанию),
-d входной файл нужно декодировать,
inFile имя входного файла, иначе стандартный ввод (input)
outFile имя выходного файла, иначе стандартный вывод (output).

Пример:
Изображение


Файлы я пока не трогала...Попыталась просто кодировать. В переменную ch сохраняю символ, если он равен следующему - увеличиваю счетчик, если нет - скидываю в строку str2 и текущий символ сохраняю снова в ch и так далее. Не работает..:

var  x, str1, str2, ch,countstr : string;
      i, k, count : integer;
begin
countstr:= '';
ch := '';
str2 := '';
count := 0;
Readln(str1);
for i := 1 to Length(str1) do begin
    if i=1 then begin
       ch:=str1[1];
       count:= 1;
    end
       else begin
            if ch= str1[i] then
               inc(count)
            else begin
                 if count > 2 then  begin
                             Str(count,countstr);
                             str2:= countstr+ch
                 end
                 else begin
                      for k := 1 to count do
                        str2 := str2+ch;
                      ch := str1[i];
                      count := 1;
                 end;
            end;
end;   
end;
end.


volvo
А если вот так попробовать:
var
  str1, str2, ch, countstr: string;
  i, k, count: integer;
begin
  str2 := '';
  { Readln(str1); }
  str1 := 'AbbCCCddddEnd';


  str1 := str1 + '_'; { <--- Последний символ не должен совпадать с добавляемым !!! }
  ch := str1[1]; count := 1;
  for i := 2 to Length(str1) do begin
    if ch = str1[i] then inc(count)
    else begin
      if count > 2 then begin
        Str(count,countstr);
        str2 := str2 + countstr + ch { <--- Здесь надо увеличивать str2 !!! }
      end
      else begin
        for k := 1 to count do
          str2 := str2 + ch;
      end;

      ch := str1[i]; count := 1; { <--- Это делается в любом случае, а не только по Else !!! }
    end;
  end;
  writeln(str2);
end.

?
lopata
Спасибо) поняла
lopata
Не получается с декодированием. Не могу понять почему больше d намного больше.



var str1 , str2, ch, substr,numberstr: string;
    number,i,j,k : integer;
begin
numberstr := '';
str2:= '';
str := 'abb3c4dend';
substr := '1234567890';
for i := 1 to Length(str1) do begin
ch := str1[i];
   if Pos(ch,substr)=0 then
      str2 := str2 + ch
      else begin
           numberstr := numberstr+ch;
           for j := i+1 to length(str1) do begin
               ch:= str1[j];
                     if pos(ch,substr)>0 then
                        numberstr := numberstr + ch
                        else begin;
                             val(numberstr,number);
                             for k := 1 to number do
                             str2 := str2+ch;
                             break;
                        end; i:= j+1;
           end;
      end;
end;



Добавлено через 17 мин.
все) сама нашла. Нужно было numberstr обнулить. Там сохранялись предыдущие числа.

end; i:= j+1;
           end;
           numberstr := '';
      end;

volvo
Цитата
end; i:= j+1;
Эту строку исправляй немедленно! smile.gif Иначе она принесет тебе немало проблем в дальнейшем. Переменная цикла для тебя - табу. Ты имеешь к ней доступ для чтения, но для записи - ни в коем случае. Компилятор сам решает, когда и как изменять эту переменную. Тебе этого делать нельзя.
lopata
Ок)
Насчет последнего исправления тоже неверно. Я так обрадавалась, что количесиво d уменьшилось, что даже не заметила что их 5 вместо 4(
Client
uses crt;
var
  str1, str2, ch, countstr: string;
  i, k, count: integer;
  errcode : integer;
begin
  str2 := '';
  ch:='';
  { Readln(str1); }
  str1 := 'Abb10C4dEn2d';
  i:=1;
  while i <= length(str1) do begin
   if str1[i] in ['0'..'9'] then begin
      while (str1[i] in ['0'..'9']) do begin
         ch:=ch + str1[i];
         inc(i);
      end;
      val(ch, count, errcode);
      if count > 2 then
         for k:=1 to count-1 do
            str2 := str2 + str1[i];
   end
   else begin
      str2 := str2 + str1[i];
      ch:='';
      inc(i);
   end;
  end;

  writeln(str2);
  readkey
end.
Попробуй так, вроде пашет
lopata
Спасибо, Client.
Просто обидно, что у меня никогда ничего не работает(

Добавлено через 14 мин.
volvo, а что у меня неправильно?/
Client
Узнаешь код
var str1 , str2, ch, substr,numberstr: string;
    number,i,j,k : integer;
    errcode: integer;
begin
numberstr := '';
str2:= '';
str1:= 'abb10c4den2d';
substr := '1234567890';
i:=1;
while  i <= Length(str1) do begin   //замена на while
   ch := str1[i];
   if Pos(ch,substr)=0 then begin
      str2 := str2 + ch;
      numberstr:='';  //обнуление
      end
      else begin
           numberstr := numberstr+ch;
           for j := i+1 to length(str1) do begin
               ch:= str1[j];
                     if pos(ch,substr)>0 then begin
                        numberstr := numberstr + ch;
                        inc(i);  //подсчет цифр
                        end
                        else begin
                             val(numberstr,number, errcode);
                             if number > 2 then  //проверка на 2
                              for k := 1 to number-1 do
                                 str2 := str2+ch;
                             break;
                             inc(i);
                        end;
           end;
      end;
      inc(i);  //на основной while для перехода к след символу
   end;
writeln(str2);
end.
?
Воть, вроде ничего не забыл.
lopata
Хм..но работает неверно.
Вадает результат abbccccccccccddend
пропустило последий символ.
А если задать abb3c4cEnd, то вообще не получается.
Client
вариант что в коде - 10 "с" и 4 "d"
Цитата
А если задать abb3c4cEnd, то вообще не получается.
То 7 "с" и получается
lopata
Сорри. Имела в виду abb3c4dEnd.
Походу я что-то недопонимаю...
volvo
Цитата
Сорри. Имела в виду abb3c4dEnd.
В чем проблема?
Нажмите для просмотра прикрепленного файла

Что ты ожидала получить?
lopata
Снова извините. Переклинило.
lopata
Не мог бы кто-нибудь объяснить про командную строку?
TarasBer
ParamCount - число параметров командной строки.
ParamStr(N) - N-ый параметр, строковый тип. ParamStr(0) - само имя программы, с полным путём к ней.
lopata
Честно говоря вообще не понимаю как это должно работать
Unconnected
Ну тебе надо получить 3 параметра, делаешь что-то типа (пишу тут):

var c,infile,outfile:string;
begin
  c:=paramstr[1];
  infile:=paramstr[2];
  outfile:=paramstr[3];
  if uppercase(c)='-D' then unpcking else packing;
end.


Естественно, надо оформить коды сжатия и разжатия в процедуры packing и unpacking или даже обойтись без процедур.
Гость
Цитата(Unconnected @ 13.04.2010 22:06) *

Естественно, надо оформить коды сжатия и разжатия в процедуры packed и unpacked или даже обойтись без процедур.

Эммм...А что это значит?
Client
это значит что надо выполнить выбранное действие
TarasBer
Что такое командная строка - знаешь? Говоря на пальцах, это то, что есть в любом нормальном файловом менеджере, там можно написать myProgram.exe, а можно написать myProgram.exe a b c d, через пробел (если же написать "myProgram.exe a" b c d, то часть, заключённая в кавычки, будет пониматься как один параметр, несмотря на то, что в ней содержится пробел). Это означает, что ты вызываешь программу myProgram.exe с параметрами a, b, c, d. То, что написано в свойствая ярлыка в строке "Объект" - это тоже команда, как правило, она там без параметров. Когда ты открываешь файл "a.txt", на самом деле вызывается команда notepad.exe a.txt, то есть в качестве параметра идёт имя открываемого файла. Поэтому все приличные программы знают, когда надо при запуске показать пустое окно, а когда - сразу открыть файл.

Программа получает информацию о них через функции ParamCount (в данном примере, с myProgram.exe a b c d - 4), и через ParamStr(N) (N от 0 до 4).
Твоя программа может принимать до 3 параметров, надо отдельно разобрать случаи разного их количества, чтобы сформировать, что программа должна делать. Типа так:

var
  Decode: boolean;
  InFile, OutFile: string;

...
  Decode := False;
  InFile := '';
  OutFile := '';
  if ParamCount >= 1 then begin
    if ParamStr(1) = '-c' then Decode := False
    else if ParamStr(1) = '-d' then Decode := True
    else InFile := ParamStr(1);
  end;
  if ParamCout >= 2 then begin
    if InFile = '' then InFile := ParamStr(2) else OutFile := ParamStr(2);
  end;
  if ParamCount >= 3 then begin
    if OutFile = '' then OutFile := ParamStr(3);
  end;

lopata
Спасибо. Стало немного понятней. А можешь привести какой-нибудь простой полный пример как это работает?
TarasBer
Ну например, программа возводит одно число в степень другого, числа задаются как параметры.


program Test;

var
  a, b: extended;
  Code: integer;

begin

  if ParamCount < 2 then begin
    WriteLn('Must be >= 2 parameters!');
    Exit;
  end;
  Val(Paramstr(1), a, Code);
  if Code <> 0 then begin
    WriteLn(Paramstr(1) , ' is not a number!');
    Exit;
  end;
  Val(Paramstr(2), b, Code);
  if Code <> 0 then begin
    WriteLn(Paramstr(2) , ' is not a number!');
    Exit;
  end;

  if a > 0 then WriteLn(exp(ln(a) * b))
  else if a = 0 then WriteLn(0)
  else if (Frac(b) = 0) and (Frac(b/2) = 0) then WriteLn(exp(ln(-a) * b))
  else if (Frac(b) = 0) then WriteLn(-exp(ln(-a) * b))
  else WriteLn('Invalid argument');

end.




Пример: в командной строке переходите в директорию с этой программой (например, cd c:\progra~1\delphi\projects\test\), потом в командной строке пишете test 2 2, она выводит 4.000000E+0000
lopata
Spasibo ogromnoje.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.