Строковый тип данных. Работа с символами и строками. Удаление части строки

Работа со строками и символами

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

Символы

Символ - это одна единица текста. Это буква, цифра, какой-либо знак. Кодовая таблица символов состоит из 256 позиций, т.е. каждый символ имеет свой уникальный код от 0 до 255. Символ с некоторым кодом N записывают так: #N. Прямо так символы и указываются в коде программы. Так как код символа представляет собой число не более 255, то очевидно, что в памяти символ занимает 1 байт. Как известно, менее байта размерности нет. Точнее, она есть - это бит, но работать с битами в программе мы не можем: байт - минимальная единица. Просмотреть таблицу символов и их коды можно с помощью стандартной утилиты "Таблица символов", входящей в Windows (ярлык расположен в меню Пуск - Программы - Стандартные - Служебные). Но совсем скоро мы и сами напишем нечто подобное.

Строки

Строка, она же текст - это набор символов, любая их последовательность. Соответственно, один символ - это тоже строка, тоже текст. Текстовая строка имеет определённую длину. Длина строки - это количество символов, которые она содержит. Если один символ занимает 1 байт, то строка из N символов занимает соответственно N байт.

Есть и другие кодовые таблицы, в которых 1 символ представлен не одним байтом, а двумя. Это Юникод (Unicode). В таблице Юникода есть символы всех языков мира. К сожалению, работа с Юникодом довольно затруднена и его поддержка пока что носит лишь локальный характер. Delphi не предоставляет возможностей для работы с Юникодом. Программная часть есть, но вот визуальные элементы - формы, кнопки и т.д. не умеют отображать текст в формате Юникода. Будем надеяться, в ближайшем будущем такая поддержка появится. 2 байта также называют словом (word). Отсюда и название соответствующего числового типа данных - Word (число, занимающее в памяти 2 байта, значения от 0 до 65535). Количество "ячеек" в таблице Юникода составляет 65536 и этого вполне достаточно для хранения всех языков мира. Если вы решили, что "1 байт - 256 значений, значит 2 байта - 2*256 = 512 значений", советую вспомнить двоичную систему и принцип хранения данных в компьютере.

Типы данных

Перейдём непосредственно к программированию. Для работы с символами и строками существуют соответствующие типы данных:

· Char - один символ (т.е. 1 байт);

· String - строка символов, текст (N байт).

Официально строки вмещают лишь 255 символов, однако в Delphi в строку можно записать гораздо больше. Для хранения больших текстов и текстов со специальными символами существуют специальные типы данных AnsiString и WideString (последний, кстати, двухбайтовый, т.е. для Юникода).

Для задания текстовых значений в Pascal используются одинарные кавычки (не двойные!). Т.е. когда вы хотите присвоить строковой переменной какое-либо значение, следует сделать это так:

Символы указываются аналогично, только в кавычках присутствует один-единственный символ.

Если вы хотите жёстко ограничить длину текста, хранимого в строковой переменной, можно сделать это следующим образом:

Поскольку каждая строка - это последовательность символов, каждый символ имеет свой порядковый номер. В Pascal нумерация символов в строках начинается с 1. Т.е. в строке "ABC" символ "A" - первый, "B" - второй и т.д.

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

var s: string; c: char; ... s:="Hello!"; c:=s; //c = "e"

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

Обработка строк

Перейдём к функциям и процедурам обработки строк.

Длину строки можно узнать с помощью функции Length(). Функция принимает единственный параметр - строку, а возвращает её длину. Пример:

var Str: String; L: Integer; { ... } Str:="Hello!"; L:=Length(Str); //L = 6

Нахождение подстроки в строке

Неотъемлемой задачей является нахождение подстроки в строке. Т.е. задача формулируется так: есть строка S1. Определить, начиная с какой позиции в неё входит строка S2. Без выполнения этой операции ни одну обработку представить невозможно.

Итак, для такого нахождения существует функция Pos(). Функция принимает два параметра: первый - подстроку, которую нужно найти, второй - строку, в которой нужно выполнить поиск. Поиск осуществляется с учётом регистра символов. Если функция нашла вхождение подстроки в строку, возвращается номер позиции её первого вхождения. Если вхождение не найдено, функция даёт результат 0. Пример:

var Str1, Str2: String; P: Integer; { ... } Str1:="Hi! How do you do?"; Str2:="do"; P:=Pos(Str2, Str1); //P = 9

Удаление части строки

Удалить часть строки можно процедурой Delete(). Следует обратить внимание, что это именно процедура, а не функция - она производит действия непосредственно над той переменной, которая ей передана. Итак, первый параметр - переменная строкового типа, из которой удаляется фрагмент (именно переменная! конкретное значение не задаётся, т.к. процедура не возвращает результат), второй параметр - номер символа, начиная с которого нужно удалить фрагмент, третий параметр - количество символов для удаления. Пример:

var Str1: String; { ... } Str1:="Hello, world!"; Delete(Str1, 6, 7); // Str1 = "Hello!"

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

Вот пример. Допустим, требуется найти в строке первую букву "a" и удалить следующую за ней часть строки. Сделаем следующим образом: позицию буквы в строке найдём функцией Pos(), а фрагмент удалим функцией Delete().

var Str: String; { ... } Str:="This is a test."; Delete(Str,Pos("a",Str),Length(Str));

Попробуем подставить значения и посмотреть, что передаётся функции Delete. Первая буква "a" в строке стоит на позиции 9. Длина всей строки - 15 символов. Значит вызов функции происходит такой: Delete(Str,9,15). Видно, что от буквы "a" до конца строки всего 7 символов... Но функция сделает своё дело, не смотря на эту разницу. Результатом, конечно, будет строка "This is ". Данный пример одновременно показал и комбинирование нескольких функций.

Копирование (извлечение) части строки

Ещё одной важной задачей является копирование части строки. Например, извлечение из текста отдельных слов. Выделить фрагмент строки можно удалением лишних частей, но этот способ неудобен. Функция Copy() позволяет скопировать из строки указанную часть. Функция принимает 3 параметра: текст (строку), откуда копировать, номер символа, начиная с которого скопировать и количество символов для копирования. Результатом работы функции и будет фрагмент строки.

Пример: пусть требуется выделить из предложения первое слово (слова разделены пробелом). На форме разместим Edit1 (TEdit), в который будет введено предложение. Операцию будет выполнять по нажатию на кнопку. Имеем:

В данном случае из строки копируется фрагмент от начала до первого пробела. Число символов берётся на единицу меньше, т.к. в противном случае пробел также будет скопирован.

Вставка подстроки в строку

Если требуется в имеющуюся строку вставить другую строку, можно использовать процедуру Insert(). Первый параметр - строка для вставки, второй - переменная, содержащая строку, куда нужно вставить, третий - позиция (номер символа), начиная с которого будет вставлена строка. Пример:

procedure TForm2.Button1Click(Sender: TObject); var S: String; begin S:="1234567890"; Insert("000",S,3); ShowMessage(S) end;

В данном случае результатом будет строка "1200034567890".

Пример "посерьёзнее"

Примеры, приведённые выше, лишь демонстрируют принцип работы со строками с помощью функций Length(), Pos(), Delete() и Copy(). Теперь решим задачу посложнее, которая потребует комбинированного применения этих функций.

Задача: текст, введённый в поле Memo, разбить на слова и вывести их в ListBox по одному на строке. Слова отделяются друг от друга пробелами, точками, запятыми, восклицательными и вопросительными знаками. Помимо этого вывести общее количество слов в тексте и самое длинное из этих слов.

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

Интерфейс: Memo1 (TMemo), Button1 (TButton), ListBox1 (TListBox), Label1, Label2 (TLabel).

Сначала перенесём введённый текст в переменную. Для того, чтобы разом взять весь текст из Memo, обратимся к свойству Lines.Text:

var Text: string; begin Text:=Memo1.Lines.Text; end;

Теперь перейдём к обработке. Первое, что нужно сделать - разобраться с символами-разделителями. Дело в том, что такие символы могут запросто идти подряд, ведь после запятых, точек и других знаков ставится пробел. Обойти эту трудность можно таким простым способом: все разделяющие символы заменим на какой-то один, например на запятую. Для этого пройдём все символы и сделаем необходимые замены. Чтобы определить, является ли символ разделителем, запишем все разделители в отдельную строковую переменную (константу), а затем будем искать в этой строке каждый символ функцией Pos(). Все эти замены будут производиться в переменной, чтобы оригинальный текст в Memo (т.е. на экране) не был затронут. Тем не менее, для проверки промежуточных результатов работы имеет смысл выводить обработанный текст куда-либо. Например, в другое поле Memo. Чтобы пройти все символы, воспользуемся циклом FOR, где переменная пройдёт порядковые номера всех символов, т.е. от 1 до длины строки текста:

procedure TForm1.Button1Click(Sender: TObject); const DelSym = " .,!?"; var Text: string; i: integer; if Pos(Text[i],DelSym) > 0 then Text[i]:=","; Memo2.Text:=Text; end;

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

if Text = "," then Delete(Text,1,1); while Pos(",",Text) > if Text <> "," then Text:=Text+",";

Здесь замена произведена следующим образом: организован цикл, в котором одна из запятых удаляется, но происходит это до тех пор, пока в тексте есть две идущие подряд запятые.

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

var Word: string; {...}

Теперь в переменной Word у нас слово из текста, а в переменной Text вся остальная часть текста. Вырезанное слово теперь добавляем в ListBox, вызывая ListBox.Items.Add(строка_для_добавления).

Теперь нам нужно организовать такой цикл, который позволил бы вырезать из текста все слова, а не только первое. В данном случае подойдёт скорее REPEAT, чем WHILE. В качестве условия следует указать Length(Text) = 0, т.е. завершить цикл тогда, когда текст станет пустым, т.е. когда мы вырежем из него все слова.

repeat Word:=Copy(Text,1,Pos(",",Text)-1); Delete(Text,1,Length(Word)+1); ListBox1.Items.Add(Word); until Length(Text) = 0;

Итак, на данный момент имеем:

procedure TForm1.Button1Click(Sender: TObject); const DelSym = " .,!?"; var Text,Word: string; i: integer; begin Text:=Memo1.Lines.Text; for i:= 1 to Length(Text) do if Pos(Text[i],DelSym) > 0 then Text[i]:=","; if Text = "," then Delete(Text,1,1); while Pos(",",Text) > 0 do Delete(Text,Pos(",",Text),1); repeat Word:=Copy(Text,1,Pos(",",Text)-1); Delete(Text,1,Length(Word)+1); ListBox1.Items.Add(Word); until Length(Text) = 0; end;

Если вы сейчас запустите программу, то увидите, что всё отлично работает. За исключением одного момента - в ListBox в конце появились какие-то пустые строки... Возникает вопрос: откуда же они взялись? Об этом вы узнаете в следующем разделе урока, а пока давайте реализуем требуемое до конца.

Количество слов в тексте определить очень просто - не нужно заново ничего писать. Т.к. слова у нас занесены в ListBox, достаточно просто узнать, сколько там строк - ListBox.Items.Count.

Теперь нужно найти самое длинное из всех слов. Алгоритм нахождения максимального числа таков: принимаем в качестве максимального первое из чисел. Затем проверяем все остальные числа таким образом: если число больше того, которое сейчас записано как максимальное, делаем максимальным это число. В нашем случае нужно искать максимальную длину слова. Для этого можно добавить код в цикл вырезания слов из текста или произвести поиск после добавления всех слов в ListBox. Сделаем вторым способом: организуем цикл по строкам ListBox. Следует отметить, что строки нумеруются с нуля, а не с единицы! В отдельной переменной будем хранить самое длинное слово. Казалось бы, нужно ведь ещё хранить максимальную длину слова, чтобы было с чем сравнивать... Но не нужно заводить для этого отдельную переменную, ведь мы всегда можем узнать длину слова функцией Length(). Итак, предположим, что первое слово самое длинное...

Почему цикл до ListBox.Items.Count-1, а не просто до Count, разберитесь самостоятельно:-)

Вот теперь всё готово!

procedure TForm1.Button1Click(Sender: TObject); const DelSym = " .,!?"; var Text,Word,LongestWord: string; i: integer; begin Text:=Memo1.Lines.Text; for i:= 1 to Length(Text) do if Pos(Text[i],DelSym) > 0 then Text[i]:=","; if Text = "," then Delete(Text,1,1); while Pos(",",Text) > 0 do Delete(Text,Pos(",",Text),1); Text:=AnsiReplaceText(Text,Chr(13),""); Text:=AnsiReplaceText(Text,Chr(10),""); repeat Word:=Copy(Text,1,Pos(",",Text)-1); Delete(Text,1,Length(Word)+1); ListBox1.Items.Add(Word); until Length(Text) = 0; Label1.Caption:="Количество слов в тексте: "+IntToStr(ListBox1.Items.Count); LongestWord:=ListBox1.Items; for i:= 1 to ListBox1.Items.Count-1 do if Length(ListBox1.Items[i]) > Length(LongestWord) then LongestWord:=ListBox1.Items[i]; Label2.Caption:="Самое длинное слово: "+LongestWord+" ("+IntToStr(Length(LongestWord))+" букв)"; end;

Работа с символами

Собственно, работа с символами сводится к использованию двух основных функций - Ord() и Chr(). С ними мы уже встречались. Функция Ord() возвращает код указанного символа, а функция Chr() - наоборот, возвращает символ с указанным кодом.

Помните "Таблицу символов"? Давайте сделаем её сами!

Вывод осуществим в TStringGrid. Этот компонент представляет собой таблицу, где в каждой ячейке записано текстовое значение. Компонент расположен на вкладке Additional (по умолчанию следует прямо за Standard). Перво-наперво настроим нашу табличку. Нам нужны всего две колонки: в одной будем отображать код символа, а в другой - сам символ. Количество колонок задаётся в свойстве с логичным названием ColCount. Устанавливаем его равным 2. По умолчанию у StringGrid задан один фиксированный столбец и одна фиксированная строка (они отображаются серым цветом). Столбец нам не нужен, а вот строка очень кстати, поэтому ставим FixedCols = 0, а FixedRows оставляем = 1.

Заполнение осуществим прямо при запуске программы, т.е. не будем ставить никаких кнопок. Итак, создаём обработчик события OnCreate() формы.

Количество символов в кодовой таблице 256, плюс заголовок - итого 257. Зададим число строк программно (хотя можно задать и в Инспекторе Объекта):

procedure TForm1.FormCreate(Sender: TObject); begin StringGrid1.RowCount:=257; end;

Вывод делается крайне просто - с помощью цикла. Просто проходим числа от 0 до 255 и выводим соответствующий символ. Также выводим надписи в заголовок. Доступ к ячейкам StringGrid осуществляется с помощью свойства Cells: Cells[номер_столбца,номер_строки]. В квадратных скобках указываются номера столбца и строки (начинаются с нуля). Значения текстовые.

Запускаем, смотрим.

Специальные символы

Если вы внимательно посмотрите на нашу таблицу, то увидите, что многие символы отображаются в виде квадратиков. Нет, это не значки. Так отображаются символы, не имеющие визуального отображения. Т.е. символ, например, с кодом 13 существует, но он невидим. Эти символы используются в дополнительных целях. К примеру, символ #0 (т.е. символ с кодом 0) часто применяется для указания отсутствия символа. Существуют также строки, называемые null-terminated - это строки, заканчивающиеся символом #0. Такие строки используются в языке Си.
По кодам можно опознавать нажатия клавиш. К примеру, клавиша Enter имеет код 13, Escape - 27, пробел - 32, Tab - 9 и т.д.

Давайте добавим в нашу программу возможность узнать код любой клавиши. Для этого обработаем событие формы OnKeyPress(). Чтобы этот механизм работал, необходимо установить у формы KeyPreview = True.

Здесь мы выводим окошко с текстом. У события есть переменная Key, в которой хранится символ, соответствующий нажатой клавише. С помощью функции Ord() узнаём код этого символа, а затем функцией IntToStr() преобразуем это число в строку.

Пример "посерьёзнее" - продолжение

Вернёмся к нашему примеру. Пришло время выяснить, откуда в ListBox берутся пустые строки. Дело в том, что они не совсем пустые. Да, визуально они пусты, но на самом деле в каждой из них по 2 специальных символа. Это символы с кодами 13 и 10 (т.е. строка #13#10). В Windows такая последовательность этих двух не визуальных символов означает конец текущей строки и начало новой строки. Т.е. в любом файле и вообще где угодно переносы строк - это два символа. А весь текст, соответственно, остаётся непрерывной последовательностью символов. Эти символы можно (и даже нужно) использовать в случаях, когда требуется вставить перенос строки.

Доведём нашу программу по поиску слов до логического конца. Итак, чтобы избавиться от пустых строк, нам нужно удалить из текста символы #13 и #10. Сделать это можно с помощью цикла, по аналогии с тем, как мы делали замену двух запятых на одну:

while Pos(Chr(13),Text) > 0 do Delete(Text,Pos(Chr(13),Text),1); while Pos(Chr(10),Text) > 0 do Delete(Text,Pos(Chr(10),Text),1);

Ну вот - теперь программа полностью работоспособна!

Дополнительные функции для работы со строками - модуль StrUtils

Дополнительный модуль StrUtils.pas содержит дополнительные функции для работы со строками. Среди этих функций множество полезных. Вот краткое описание часто используемых функций:

PosEx (подстрока, строка, отступ) - функция, аналогичная функции Pos(), но выполняющая поиск с указанной позиции (т.е. с отступом от начала строки). К примеру, если вы хотите найти в строке второй пробел, а не первый, без этой функции вам не обойтись. Чтобы сделать поиск второго пробела вручную, нужно предварительно вырезать часть из исходной строки.

AnsiReplaceStr, AnsiReplaceText (строка, текст_1, текст_2) - функции выполняют замену в строке строка строки текст_1 на текст_2. Функции отличаются только тем, что первая ведёт замену с учётом регистра символов, а вторая - без него.

В нашей программе можно использовать эти функции для вырезания из строки символов #13 и #10 - для этого в качестве текста для замены следует указать пустую строку. Вот решение в одну строку кода:

Text:=AnsiReplaceText(AnsiReplaceText(Text,Chr(13),""),Chr(10),"");

DupeString (строка, число_повторений) - формирует строку, состоящую из строки строка путём повторения её заданное количество раз.

ReverseString (строка) - инвертирует строку ("123" -> "321").

Также следует упомянуть у функциях преобразования регистра.

UpperCase (строка) - преобразует строку в верхний регистр; LowerCase (строка) - преобразует строку в нижний регистр.

Для преобразования отдельных символов следует использовать эти же функции.

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

Скриншоты программ, описанных в статье

Заключение

Длинный получился урок. Итак, сегодня мы познакомились со строками и символами и научились с ними работать. Изученные приёмы используются практически повсеместно. Не бойтесь экспериментировать - самостоятельно повышайте свой уровень навыков программирования!

Министерство образования и науки Российской Федерации

Федеральное агентство по образованию

Саратовский государственный технический университет

Балаковский институт техники, технологии и управления

Работа с символами и строками в языке программирования си

Методические указания к выполнению лабораторной работы по курсу «Логическое программирование» для студентов специальности 071900 дневной формы обучения

Одобрено

редакционно-издательским советом

Балаковского института техники,

технологии и управления

Балаково 2009

ЦЕЛЬ РАБОТЫ : познакомиться с понятиями символьной, строковой переменной, строковой константы, указателя на строки, научиться выполнять операции ввода/вывода строк, определять специфику работы со строковыми функциями.

1. Общие понятия

В данной работе рассматриваются символьные переменные, строковые переменные и константы, операции ввода/вывода строк, основные функции работы со строками.

1.1. Символьные переменные

Любой текст состоит из символов. Для хранения одного символа предназначен тип данных char . Переменную типа char можно рассматривать двояко:

    как целое число, занимающее 1 байт и способное принимать значения:

    • от 0 до 255 (тип unsigned char );

      от -128 до 127 (тип signed char );

    как один текстовый символ.

Сам же тип char может оказаться как знаковым, так и беззнаковым, в зависимости от операционной системы и компилятора. Поэтому использовать тип char не рекомендуется, лучше явно указывать, будет ли он знаковым (signed ) или беззнаковым (unsigned ).

Как и целые числа, данные типа char можно складывать, вычитать, умножать, делить, а можно выводить на экран в виде одного символа.

Если нужно вывести числовое значение символа, также называемое ASCII-кодом, то значение символа необходимо преобразовать к типу int . Например:

#include

using namespace std;

unsigned char c="A"; // Константы char заключаются в одинарные кавычки

cout<

c=126; // char можно присвоить и числовое значение

cout<

В этом примере переменной с типа char присваивается значение, равное символу "A" (константы типа char записываются как символы в одинарных кавычках), затем на экран выводится значение c как символа и его ASCII-код, потом переменной c присваивается значение 126, то есть символ с ASCII-кодом 126 и снова выводится на экран символ и его ASCII-код.

1.2. Строковые переменные и константы

Текстовую строку можно представить, как массив символов типа char , но в языке СИ для хранения текстовых строк был создан более удобный тип string .

Строковые переменные используются для хранения последовательности символов.

Строковые переменные должны быть объявлены перед тем, как начнется их использование. Объявление строковой переменной выглядит следующим образом: char s,

где s рассматривается как массив с элементами символьного типа, который может содержать до 14 элементов. Предположим, что s присваивается строковая константа:

Я ПРОГРАММИСТ!

Строковая константа – это последовательность символов, заключенная в кавычки. Каждый символ строки хранится как элемент массива. В памяти строка хранится следующим образом:

Символ ‘\0’ нуль (null) – символ автоматически добавляется к внутрисистемному представлению строки для того, чтобы в программе можно было определить конец строки. Таким образом, при описании строковой переменной следует предусматривать один дополнительный элемент для завершающего нуль-символа.

Строки также могут вписываться в память и считываться при помощи символьных указателей. Символьный указатель на строку объявляется следующим образом: char *pstr = ЗДРАВСТВУЙ,

где pstr это указатель, который инициализирован ссылкой на строковую константу. Указатель может быть изменен так, что он будет указывать на какой-либо другой адрес, но при этом строка, на которую изначально ссылался указатель, может стать недоступной.

Работа с текстовыми данными предполагает использование типов данных CHAR или STRING соответствующей длины. Для обработки данных этого типа в языках предлагается, кроме обычных операций, набор функций и процедур существенно сокращающих записи операций типа поиска символа в строке- POS(s1,s), вставки символа Insert(s1,s,n), удаление символа Delete(s,n,m), копирование символа строки Copy(s,n,m), определение длины строки Length(s), слияние строк- конктенация Concat(s1,s2,...,sn).

1.2.1. Вводится некоторое количество строк. В каждой строке - последовательность слов, разделенных хотя бы одним пробелом. Расположить в каждой строке слова по возрастанию их длины.

1.2.2. Дана строка, длиной не более 80 символов. Подсчитать количество повторений каждой встречающейся в строке буквы. Напечатать результат обработки в форме:

< буква > < количество повторений > < исходная строка>

1.2.3. Дана строка символов А. Удалить из строки все повторяющиеся символы, вывести исходную строку и результат обработки.

1.2.4. Дана строка из N букв. Разбить строку по m букв. Вывести исходную строку и результат обработки строки.

1.2.5. Дана строка из N букв. Разбить строку на K слов, в каждом из которых не более m букв. Вывести исходную строку и результат обработки строки.

1.2.6. Дана последовательность из строк с сообщениями: город, время вылета самолета, время в пути. Написать программу упорядочивания сообщений по времени в пути. Вывести исходные данные и результат обработки.

1.2.7. Дана последовательность слов в виде некоторого текста. К каждому слогу в словах текста добавить по новому слогу -”NO”. Слова в исходном тексте разделяются, по крайней мере, хотя бы одним пробелом. Вывести исходный текст и результат обработки текста.

1.2.8. Дан текст из некоторого количества предложений. Предложения разделяются знаком “;”. Разделить текст на отдельные предложения по этому знаку. Вывести исходный текст и результат обработки текста.

1.2.9. Дана строка из неизвестного заранее количества букв. Упорядочить все символы в строке по алфавиту. Вывести исходную строку и результат обработки строки.



1.2.10. Дана английская фраза из слов, разделенных хотя бы одним пробелом. Расположить слова по одному в каждой строке и упорядочить слова по алфавиту. Вывести исходную строку и результат обработки строки.

1.2.11. Вводится произвольное количество строк. Определить сколько раз в каждой строке повторяются одинаковые буквы. Вывести исходные строки и результат обработки строк.

1.2.12. Вводится произвольный текст из неизвестного количества строк. Разделить текст на строки и упорядочить по 1-ой букве строки. Конец каждой строки может быть любым из символов “. , ;”. Вывести исходный текст и результат обработки.

1.2.13. “Это я знаю и помню прекрасно пи многие знаки мне лишни напрасны”. Ввести фразу и напечатать полученное значение числа p. Проверить работоспособность программы на любом произвольном тексте. Вывести исходный текст и результат вычислений.

1.2.14. Дан текст из слов, разделенных пробелами. Выделить из текста слова, состоящие их 4, 5, 6 букв. Напечатать исходный текст и результат его обработки.

1.2.15. Дана строка из неизвестного количества символов. Исключить из последовательности K-ый элемент, сжать строку. Вставить за M-ым элементом новый элемент. Количество удалений и вставок - любое. Вывести исходную строку и все результаты преобразований.

1.2.16. Задан текст из латинских букв. Вывести в алфавитном порядке все буквы, которые встречаются в тексте только один раз. Вывод исходного текста обязателен.

1.2.17. Дан текст из K символов. Преобразовать текст, заменив все не одиночные пробелы одним пробелом, все точки - точкой с запятой, все многоточия - одной точкой. Вывести исходный текст и результат обработки текста.

1.2.18. Вводится последовательность строк. Определить для каждой строки количество слов разной длины. Например,

в i -ой строке 5 слов длины 4 буквы

3 слова длины 8 букв и т. д.

Вывести на экран исходный текст и результат его обработки.

1.2.19. Вводится некоторая произвольная фраза на английском языке. Выделить из фразы две последовательности: гласных и согласных букв. Вывести исходный текст и результат его обработки.

1.2.20. Вводится текст, разбитый на две строки знаком “;”. Удалить из этой пары строк все повторяющиеся символы, общие для этой пары строк.. Вывести на экран исходный текст и результат его преобразования.

1.2.21. Вводится произвольное количество строк. Определить максимальное число подряд расположенных символов, совпадающих с первым или последним символами в каждой строке. Вывести исходный текст и результат его обработки.

1.2.22. Вводится произвольный текст из некоторого количества строк. Обеспечить выравнивание текста по количеству символов в строке за счет размещения дополнительных пробелов в строках. Количество символов в строке перед каждой операцией выравнивания задается с клавиатуры. Вывести исходный текст и результат его обработки.

1.2.23. Вводится произвольный текст, разбитый на строки знаком” ; “. Слова в строке разделены, по крайней мере, одним пробелом. Выделить в каждой строке слова в которых: а) первые буквы слов совпадают; б) длина слова - наибольшая в строке. Вывести исходный текст и результат его обработки.

1.2.24. Каждая строка текста содержит цифры десятичной системы счисления и символы - знаки “+” или “- “. Строка заканчивается знаком “=“, пробелы в строке должны игнорироваться. Получить арифметическое значение вводимого выражения. Пример: 9+5-3=11.Вывести исходный текст и результат его обработки.

1.2.25. Вводится некоторая последовательность строк. В каждой строке слова переставить в обратном порядке. Пример: fdc, ads, 2.5cx, hjkl. преобразуется в hjkl, 2.5cx, ads,fdc. Вывести исходный текст и результат его обработки.

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

1.2.27. Дана строка из английских слов. Выделить из строки подстроки из согласных букв, у которых и справа и слева стоят гласные буквы. Вывести исходную строку и результат ее обработки.

1.2.28. Дана строка длиной не более 80 символов. Строка представляет из себя запись некоторой математической формулы. Проверить правильность записи формулы по открывающим “(” и закрывающим скобкам “)”.

1.2.29. Дана строка из некоторого количества слов. Слова разделены в строке знаками “, ”, “ пробел”. Вставить произвольное новое слово в строку за i -ым словом. Вывести исходную строку и результат ее преобразования.

1.2.30. Вводится строка произвольной длины. Определить количество одинаковых подряд стоящих символов. Вывести исходную строку и результат обработки строки.

1.2.31. Заданная строка символов должна быть преобразована вычеркиванием всех символов, стоящих до первой точки в строке и после последней точки с запятой.

Символ

Символ – это один знак. Любой – буква, цифра, арифметический знак или пробел , знак препинания или подчеркивания... А также специальные символы – переход на новую строку, BackSpace, знак доллара или процент . Тип "символ" в Delphi обозначается Char:

ShowMessage("Вы ввели " + c);

ShowMessage("Переход на новую" + c + "строку");

Мы уже говорили, что символы берутся из таблицы символов ANSI или UNICODE. Большинство символов используются, некоторые символы являются служебными. Обратите внимание, что большая буква "А" и маленькая "а" - это разные символы! Также разными символами являются латинская "с" и русская "с", хотя они похожи, как две капли воды.

Нулевой символ не используется, он зарезервирован как полный нуль. Программисты нашли достойное применение этому символу, используя его в событиях ввода текста, когда требуется запретить пользователю ввод каких-либо символов. Служебные символы мы не можем увидеть в текстовом поле . Служебные символы, это , <Enter >, <Tab > и другие. Каждый символ обрабатывается компьютером как число от 0 до 255, таким образом, слово "ПРИВЕТ" в памяти машины будет выглядеть как набор цифр: "207 208 200 194 197 210".

Функции работы с символами

В практике часто приходится обрабатывать отдельные символы. Переменным символьного типа Char можно присваивать значения таким образом:

Поскольку для компьютера символ – число, то символьные данные можно сравнивать между собой. При этом большим будет тот символ, число которого в таблице символов больше. Например, "я" будет больше, чем "а":

if b > c then ShowMessage("Истина!")

else ShowMessage("Ложь!");

При работе с символьными переменными часто используют функции Chr() и Ord(). Функция Chr() принимает в качестве параметра число, и возвращает символ, который соответствует этому числу в таблице ANSI :

function Chr (X: Byte): Char;

Функция Ord() совершает прямо противоположное действие, она принимает в качестве параметра символ, и возвращает число, под которым этот символ хранится в таблице ANSI :

function Ord (C: Char): Byte;

Символьные переменные можно использовать с этими функциями:

В первой строке в переменную a мы записали символ "И", которому в таблице символов соответствует номер 200. Во вторую, целую переменную, мы записали число 200, так как символ с этим номером был записан в переменную a, которую мы передали в качестве параметра. Наконец, в третьей строке мы в целую переменную записали число 102, этот номер соответствует символу "f".


Строка

Строка – это набор символов. Строку можно представить в виде статичного или динамичного массива символьных данных. Типы строк мы уже разбирали в "Управляющая конструкция if, цикл for" : AnsiString – строка из ANSI – символов, и WideString – строка из UNICODE – символов.

Тип String не является отдельным типом, по умолчанию он равен AnsiString. Однако его можно перенастроить и наWideString , хотя в этом нет необходимости. Поэтому смело указывайте строковые переменные, как String:

s:= "Это многострочная" + #13 + "строка";

Как видно из примера, строку можно составлять из нескольких подстрок, и даже добавлять в нее отдельные символы. В примере мы добавили символ под номером 13, это символ перехода на новую строку. В результате выполнения этого кода процедураShowMessage() выведет на экран сообщение, разбитое на две строки:

Это многострочная

ShortString – короткая строка из ANSI – символов. Может содержать от 0 до 255 символов. Используется нечасто. Собственно, вы можете объявить тип String с заранее указанным размером:

Как видите, строка объявляется с числовым индексом, почти как массив . Собственно, строка символов и есть массив символьных данных, и обращаться с ней можно также. Индексация символов в строке начинается с единицы, то есть, индексу 1 соответствует 1-й символ строки.

stroka:= "Привет";

stroka := "а"; //изменили 5-й символ строки

ShowMessage(stroka); //результат: строка "Приват"

Это тоже строка, и в будущем нам придется с ней сталкиваться. Эта строка работает совершенно иначе, чем String. СтрокаString представляет собой массив символов, в нулевом элементе которого содержится количество байт , отводимых под эту строку. А переменная типа PChar – это не сама строка, а указатель на начало строки, то есть переменная указывает на первый символ строки в памяти компьютера. А где же тогда PChar хранит количество байт в строке?! А нигде! Мы уже говорили о таблице символов ANSI , и выяснили, что нулевой символ – пустой. Вот последний символ PChar как раз и хранит этот символ, икомпьютер , найдя его, считает, что строка окончена.

Со строками PChar работать очень неудобно, однако нам придется это делать, когда мы будем работать с функциями WinAPIнапрямую. Функции WinAPI – это функции самой Windows , а не Delphi. Однако Delphi позволяет использовать их. Иногда это бывает необходимо, например, когда средств Delphi недостаточно для выполнения намеченной задачи. Использование таких функций не всегда удобно, однако они выполняются процессором намного быстрее, так как содержатся в самой операционной системе. Пример – функция MessageBox().

Вы уже привыкли выводить сообщения с помощью функции Delphi ShowMessage()? Привыкайте к новой функции!

Application.MessageBox("строка 1", "строка 2",[ кнопки + тип_окна]);

· строка 1 - выводит текст внутри окна.

· строка 2 – текст в заголовке окна.

Если не указывать [кнопки + тип_окна] то выйдет простое окно с кнопкой ОК, как в функции ShowMessage().

Важные заметки

Неизменяемость

В JavaScript строки являются неизменяемыми, так же говорят "immutable". Это означает, что какие бы вы к ним не применяли функции, они не производят in-place замены (то есть не производят изменения самой строки). Любые строковые функции, примененные к строкам, возвращают новую строку. Это верно и в том случае, когда мы обращаемся к конкретному символу в строке.

Const str = "hello"; str.toUpperCase(); // HELLO console.log(str); // hello str.toUpperCase(); // H console.log(str); // hello str = "W"; console.log(str); // hello

Лексикографический порядок

Лексикографический порядок - это, другими словами, алфавитный порядок. Такой порядок используется в словарях, телефонных справочниках, записных книжках и так далее.

В JavaScript вы можете сравнивать строки с помощью > и < , и сравнение будет происходить именно лексикографически.

Помните, "8" это не число, а строка.

Интерполяция

Кроме одиночных "" и двойных кавычек "" , современный JavaScript содержит обратные тики (backticks):

``

С обратными тиками вы можете использовать интерполяцию , вместо конкатенации. Вот, смотрите:

Const name = "Alex"; const a = 10; const b = 12; console.log(`His name was ${name} and his age was ${a + b}`);

Такой код выведет на экран His name was Alex and his age was 22 . Внутрь ${} вы можете поместить любое выражение.

Интерполяция предпочтительнее конкатенации . Мы советуем не использовать конкатенацию вообще. Вот некоторые из причин:

  • Такой код заставляет больше думать, потому что синтаксически + больше смахивает на сложение.
  • Из-за слабой типизации можно легко получить не тот результат. Конкатенация может породить ошибки.
  • Сложные строки при использовании конкатенации невозможно нормально разобрать в голове и понять, как они устроены.

Конспект урока

  • Строка - это последовательность символов
  • Пустая строка - это тоже строка (последовательность нуля символов)
  • Обозначается единичными или двойными кавычками

Создание строки с константой:

Const str1 = "Hello"; const str2 = "Hello";

Возможно включить кавычку одного типа внутрь строки, окружив её кавычками другого типа:

Const str1 = "They call him "Harry", and he likes it"; const str2 = "They call him "Harry", and he likes it";

Если в строке используются кавычки того же типа, они должны быть экранированы с помощью обратного слеша \ :

Const str1 = "They call her \"Ann\", and she likes it"; const str2 = "They call her \"Ann\", and she likes it";

Если строка включает обратный слеш (именно как символ, который хочется иметь в строке), он должен быть экранирован другим обратным слешем:

Const str = "This is a backslash \\ here" // This is a backslash \ here

Так же существуют управляющие символы - специальные комбинации, которые генерируют невидимые детали:

Const str = "There is a tab \t and here \ncomes the new line!" // Here is a tab and here // comes the new line!

\t - это табуляция, \n это перенос на новую строку. Больше об экранировании (англ) .

Конкатенация строк

Строки могут склеиваться друг с другом. Такой процесс называется конкатенацией и задаётся символом + :

Const name = "Alex"; const age = 22; console.log("His name is " + name + " and his age is " + age); // His name is Alex and his age is 22

Строки будут склеены в том порядке, в котором они указаны: "mos" + "cow" → "moscow" , а "cow" + "mos" → "cowmos"

Доступ к индивидуальным символам

str[i] это i-ый символ строки str , начинающейся с 0. Например, "hexlet" это h , а "hexlet" это x .

Вот функция, которая принимает строку и возвращает копию этой строки без каждой второй буквы. Например, "hexlet" становится "hxe".

Const skip = (str) => < str.length) { result = result + str[i]; i = i + 2; } return result; }

str.length это длина str , то есть количество символов. Это просто количество, поэтому мы не начинаем отсчёт от 0. Например, "food".length это 4.

Транскрипт урока

Помните свою первую программу "hello, world"?

Console.log("Hello, World!");

Сейчас вы уже знаете, что здесь происходит вызов функции, а функция console.log принимает аргумент. В данном случае аргумент - не число, а "строка". Так мы называем фрагменты текста в программировании, потому что они как последовательность букв на веревке.

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

Так же, как мы это делали с числами, мы можем создать константу из строки:

Const str = "Hello";

Вы можете использовать одиночные кавычки или двойные, не так важно, главное чтобы они были одинаковые и в начале и в конце строки.

Если вам необходимо использовать реальные кавычки внутри строки, тогда используйте другой знак для её создания. Например:

Const str = "They call him "Harry", and he likes it"; ///They call him "Harry", and he likes it

Здесь одиночные кавычки используются для формулирования или ограничения строки, и тогда у нас есть возможность поставить двойные внутри. Или наоборот:

Const str = "They call him "Harry", and he likes it"; /// They call him "Harry", and he likes it

Двойные снаружи - одиночные внутри.

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

Const str = "They call him "Harry", and he likes it";

то получите ошибку, потому что ваша строка поломана. Программа сломается в этом месте, потому что тут присутствует вторая закрывающая кавычка такого же типа, а затем идёт странное слово, которое ничего не означает, а потом новая строка. Это неправильный JavaScript.

Нам нужно объяснить интерпретатору JavaScript, что некоторые кавычки он должен воспринимать иначе. Они не должны означать "начало строки" или "конец строки", они должны означать "символ кавычек".

Это называется "экранированием". Добавьте символ экранирования, обратный слеш \ перед символом, и символ "изолируется" от своей специфической роли и превратится в обычный знак в строке.

Const str = "They call him \"Harry\", and he likes it"; const str2 = "They call her \"Ann\", and she likes it"; // They call him "Harry", and he likes it // They call her "Ann", and she likes it

Этот символ экранирования может использоваться для вставления других специальных символов в строку.

Тут есть три момента.

Первый: если нам нужен обратный слеш в строке, то он должен быть экранирован другим обратным слешем.

Второе: обратный слеш-t это не "экранируемый t-символ": вам не нужно экранировать "t", "t" - это не специальный символ; вся конструкция обратный слеш-t - это специальная управляющая последовательность - она представляет собой единичную табуляцию, по сути - длинный пробел.

Третье: обратный слеш-n - это другая управляющая последовательность, которая представляет собой новую строчку. Считай, что вы нажмёте клавишу Enter, когда набираете текст. Поэтому, всё, что следует дальше, перейдет на новую строчку.

Теперь давайте попробуем написать функцию. Она будет принимать строку - имя и возвращать другую строку - приветствие. Вот как это должно работать:

Const result = greet("Sherlock"); // "Well hello, Sherlock"

Эта функция должна уметь каким-то образом принимать входящую строку и склеивать её с другой строкой. Такой процесс называется "конкатенацией" и в JavaScript он реализуется знаком плюс, как при сложении чисел:

Const greet = (str) => { return "Well hello, " + str; }

Теперь другой пример. Эта функция принимает строку и возвращает ту же строку, но без каждой второй буквы. Например, "California" становится "Clfri".

Const skip = (str) => { let i = 0; let result = ""; while (i < str.length) { result = result + str[i]; i = i + 2; } return result; }

Такие квадратные скобки позволяют нам получать индивидуальные символы из строки. Как и во многих процессах в программировании, вы начинаете отсчёт с 0, а не от 1. Поэтому первый символ str это str , второй - str , и так далее. Это число называется "индексом".

Функция skip принимает аргумент, создаёт две переменных - i для счётчика и result для итоговой строки. Счётчик - это 0, потому что нам нужно начать с первого символа, а result это пустая строка - мы будем добавлять символы к ней один за другим.

Затем следует цикл while, с условием, что "i меньше, чем длина строки". Длина означает "сколько символов". Длина строки "cats" - 4 - в ней 4 символа, 4 буквы.

Пока счётчик мешьше, чем длина, мы склеиваем или конкатенируем результирующую строку с символом по индексу i. Затем добавляем 2 к счётчику. Два, а не один, потому что нам нужно пропустить один символ.

В какой-то момент счетчик станет достаточно большим для того, чтобы условие цикла стало ложным, и функция вернёт result .

Давайте попробуем вызвать функцию с аргументом "cats":

Const skipped = skip("cats");

Длина "cats" - 4. Несмотря на то, что индексы начинаются с 0, длина - это действительное количество. "c" - не 0 букв, это одна буква. Поэтому длина "cats" - 4, но индекс его последней буквы - 3.

  1. 0 меньше четырёх, поэтому войти в цикл while
  2. конкатенировать строку с символом по индексу 0 - это "c"
  3. увеличить счётчик на 2
  4. 2 меньше 4, поэтому повторить
  5. конкатенировать строку с символом по индексу 2 - это "t". строка теперь стала "ct"
  6. увеличить счётчик на 2
  7. 4 не меньше 4, поэтому больше не повторять
  8. вернуть результат - "ct"

Вас ждут тест и практическое упражнение.