Nickolay.info. Алгоритмы. Разбор на слова за 1 проход по строке

Во-первых, часто требуется определить самое длинное (или самое короткое) слово. В этой главе я привожу 2 примера такого разбора, но первый неэффективен (использует много стандартных функций, портит исходную строку, удаляя из неё уже обработанные слова), а второй ценен лишь идеей сделать разбор на слова за один проход по строке. Однако обе приведённые в пособии программы могут быть удобны, если выделяемые из строки слова должны как-то дополнительно обрабатываться.

Между тем, обычно набор допустимых символов в словах ограничен условием задачи (давайте возьмём для примера только латинские и русские буквы и цифры), а сами слова сохранять и дополнительно обрабатывать не требуется. Учитывая, что в Паскале есть удобный оператор in, напишем такую программу:

Разбор на слова за 1 проход с использованием in и определением самого длинного слова. Слова при этом не сохраняются.

var s:string;
 c:char;
 i,all,len,maxlen:integer;
begin
 writeln ('Введите предложение:');
 readln (s);
 len:=0;
 maxlen:=0;
 all:=length(s);
 for i:=1 to all do begin
  c:=s[i];
  if c in
   ['a'..'z','A'..'Z','0'..'9','а'..'п','р'..'я','А'..'П','Р'..'Я','Ё','ё']
   then inc (len)
  else begin
   if len>maxlen then maxlen:=len;
   len:=0;
  end;
 end;
 write ('Maxlen=',maxlen);
 reset (input); readln;
end.

Если бы мы захотели вывести само слово, это не потребовало бы дополнительных переменных или циклов обработки. Достаточно запоминать позицию символа pos, в которой закончилось очередное слово, а затем вывести maxlen символов, начиная с позиции pos-maxlen. Вот изменённая программа:

Разбор на слова за 1 проход с использованием in и определением самого длинного слова. Находится одно слово, оно при этом выводится. Дефисы и т.п. символы не учитываются.

var s:string;
 c:char;
 i,all,len,maxlen,pos:integer;
begin
 writeln ('Введите предложение:');
 readln (s);
 len:=0;
 maxlen:=0;
 all:=length(s);
 for i:=1 to all do begin
  c:=s[i];
  if c in
   ['a'..'z','A'..'Z','0'..'9','а'..'п','р'..'я','А'..'П','Р'..'Я','Ё','ё']
   then inc (len)
  else begin
   if len>maxlen then begin maxlen:=len; pos:=i; end;
   len:=0;
  end;
 end;
 writeln ('Maxlen=',maxlen);
 write ('Word=',Copy(s,pos-maxlen,maxlen));
 reset (input); readln;
end.

Наконец, в слова входят не только буквы и цифры, например, слова с дефисом наша программа никак не учитывает. Попробуем изменить код так, чтобы "буквой" считалось всё, что не является концом слова. Так как число допустимых между словами разделителей заведомо невелико, начать разбор в этом случае будет уместнее как раз с них.

Разбор на слова за 1 проход с использованием in и определением самого длинного слова. Находится одно слово, оно при этом выводится. Концом слова считается фиксированный набор разделителей.

var s:string;
 c:char;
 i,all,len,maxlen,pos:integer;
begin
 writeln ('Введите предложение:');
 readln (s);
 len:=0;
 maxlen:=0;
 all:=length(s);
 for i:=1 to all do begin
  c:=s[i];
  if c in [' ','.',',','?','!',':',';'] then begin {разделители}
   if len>maxlen then begin maxlen:=len; pos:=i; end;
   len:=0;
  end
  else inc(len);
 end;
 writeln ('Maxlen=',maxlen);
 write ('Word=',Copy(s,pos-maxlen,maxlen));
 reset (input); readln;
end.

Пример выдачи этой программы:

Введите предложение:
Скажи-ка, дядя, ведь недаром?
Maxlen=8
Word=Скажи-ка

Если мы хотим вывести все слова наибольшей длины, можно при первом проходе найти maxlen, а при втором, как только попадётся слово с длиной len=maxlen, напечатать его:

var s:string;
 c:char;
 i,all,len,maxlen,pos:integer;
begin
 writeln ('Введите предложение:');
 readln (s);
 len:=0;
 maxlen:=0;
 all:=length(s);
 for i:=1 to all do begin
  c:=s[i];
  if c in [' ','.',',','?','!',':',';'] then begin {разделители}
   if len>maxlen then begin maxlen:=len; pos:=i; end;
   len:=0;
  end
  else inc(len);
 end;
 writeln ('Maxlen=',maxlen);
 write ('Words=');
 for i:=1 to all do begin
  c:=s[i];
  if c in [' ','.',',','?','!',':',';'] then begin {разделители}
   if len=maxlen then write (' ',Copy(s,i-maxlen,maxlen));
   len:=0;
  end
  else inc(len);
 end;
 reset (input); readln;
end.

Соответственно, пример выдачи:

Введите предложение:
Скажи-ка, дядя, ведь не даром идут гаишники с радаром?
Maxlen=8
Words= Скажи-ка гаишники

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

readln (s); s:=s+' ';

или же предумотреть в цикле обработки отдельную проверку на то, не является ли допустимый символ последним в строке (выполняется условие i=all). Можно сделать и дополнительное сравнение значений len и maxlen после выхода из цикла разбора - ведь последнее значение len не потеряется. В этом случае конец первой программы изменится так:

  end;
 end;
 if len>maxlen then maxlen:=len;
 write ('Maxlen=',maxlen);
 reset (input); readln;

Рейтинг@Mail.ru

вверх гостевая; E-mail