Задачи на обработку стрингов

Давно хотелось вернуться к этому вскользь пройденному материалу, так как многие интересные вопросы остались не совсем понятыми, многие - совсем непонятыми.
Сначала хотелось бы разобрать те задачи, которые непосредственно давались в качестве домашних или контрольных. Чуть позже я планирую разместить еще несколько интересных задач.
Задача 1. Дана строка, состоящая из слов в латинском алфавите, которые могут быть разделены как пробелами, так и запятыми, за которыми могут следовать пробелы. Вывести на экран каждое слово в отдельной строке. Пример входной строки:

  1. red    orange,yellow green, blue
  2. one two,three,   four five     six, seven

Задача 2. Дана строка длины <= 255, представляющая собой текст в латинском алфавите, соответствующий правилам компьютерного набора, в котором могут встречаться пробелы и знаки препинания: «.», «,», «!», «?». Вывести на экран число его предложений, слов и максимальную из длин слов. Пример входной строки:
  1. Pascal is an influential imperative and procedural programming language. Pascal was developed by Niklaus Wirth and based on the ALGOL programming language.
  2. To do a great right do a little wrong.

Задача № 1

Эта задача была дана на одном из семинаров подгруппы 1ПМ Валерия Шахамболетовича. Ее можно было решить несколькими способами, однако я остановился на однократной циклической обработке с использованием стринговых операций.

  1. program SpacesAndCommas;
  2.  
  3. var
  4.   s: string;
  5.   Position, CommaPos: byte;
  6.  
  7. begin
  8.   readln(s);
  9.   Position := pos(' ', s); // находим позиции
  10.   CommaPos := pos(',', s); // разделителей
  11.   while (Position <> 0) or (CommaPos <> 0) do begin // если нашли хотя бы один из них
  12.     if (Position <> 0) and (CommaPos <> 0) then begin // если нашли оба
  13.       if CommaPos < Position then begin
  14.         Position := CommaPos // то будем работать с тем, который расположен левее
  15.       end;
  16.     end
  17.     else if Position = 0 then begin // если первый не существует
  18.       Position := CommaPos // то второй существует по условию входа в цикл, обратный случай обрабатывается по умолчанию
  19.     end;
  20.     writeln(copy(s, 1, Position - 1)); // выводим первое найденное слово
  21.     while (s[Position + 1] = ',') or (s[Position + 1] = ' ') do begin // если после текущего разделителя есть еще
  22.       inc(Position) // то увеличиваем правую границу удаления
  23.     end;
  24.     delete(s, 1, Position); // удаляем выведенное на экран слово вместе с последующими разделителями
  25.     Position := pos(' ', s); // инициализация значений
  26.     CommaPos := pos(',', s) // для последующих шагов цикла
  27.   end;
  28.   writeln(s) // если произошел выход из цикла - в стринге осталось единственное слово
  29. end.

Задача № 2

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

  1. program AnalysisOfTheText;
  2.  
  3. var
  4.   s, z: string;
  5.   p, LastChar, NumOfSentences, NumOfWords, MaxLength: byte;
  6.  
  7. begin
  8.   NumOfSentences := 1; // учитываем последнее предложение
  9.   NumOfWords := 1; // и последнее слово
  10.   MaxLength := 0;
  11.   readln(s);
  12.   p := pos(' ', s);
  13.   while p <> 0 do begin
  14.     z := copy(s, 1, p - 1); // рассматриваем каждое слово в отдельности
  15.     LastChar := length(z); // длина слова равна позиции последнего символа
  16.     if z[LastChar] = ',' then begin // если к слову присоединена запятая
  17.       delete(z, LastChar, 1); // убираем ее
  18.       dec(LastChar); // и уменьшаем длину слова на единицу
  19.     end
  20.     else if (z[LastChar] = '.') or (z[LastChar] = '!') or (z[LastChar] = '?') then begin // если конец предложения
  21.       inc(NumOfSentences); // увеличиваем счетчик предложений
  22.       delete(z, LastChar, 1); // удаляем найденный знак
  23.       dec(LastChar) // и уменьшаем длину слова на единицу
  24.     end;
  25.     if LastChar > MaxLength then begin // если длина рассматриваемого слова больше найденной максимальной
  26.       MaxLength := LastChar // запоминаем ее значение
  27.     end;
  28.     inc(NumOfWords); // увеличиваем счетчик слов
  29.     delete(s, 1, p); // и удаляем рассмотренное слово
  30.     p := pos(' ', s) // запоминаем позицию пробела для следующего шага цикла
  31.   end;
  32.   LastChar := length(s) - 1; // учитываем наличие знака препинания в конце последнего предложения
  33.   if LastChar > MaxLength then begin // отдельно обрабатываем длину последнего слова
  34.     MaxLength := LastChar
  35.   end;
  36.   writeln('Number of sentences: ', NumOfSentences); // вывод результатов
  37.   writeln('Number of words: ', NumOfWords);
  38.   writeln('Maximum length of word: ', MaxLength)
  39. end.

Ваши решения можно принять,

Ваши решения можно принять, Данил.
Решение первой задачи упростил бы предварительный цикл типа:

  1. p:=pos(',',s);
  2. While p<>0 do begin
  3.    s[p]:=' ';
  4.    p:=pos(',',s);
  5. End;  

Кстати, решение в один проход не самоцель