Символы и строки (PascalABC.NET): различия между версиями

Материал из Информационная безопасностя
Перейти к навигации Перейти к поиску
Строка 225: Строка 225:
 
#1072..#1103;
 
#1072..#1103;
 
* буква 'ё' имеет десятичный код #1105.
 
* буква 'ё' имеет десятичный код #1105.
 +
 +
== Выделение подстроки ==
 +
Подстрока – это часть строки, полученная путем выборки некоторых ее символов, следующих подряд.
 +
* расширение s.Left(k) возвращает k левых символов строки s;
 +
* расширение s.Right(k) возвращает k правых символов строки s.
 +
Для получения подстроки удобно использовать срезы. Легче запоминается, короче запись.
 +
 +
== Срезы строк ==
 +
Срезы строк реализуются аналогично, но возвращают они подстроку, а не последовательность или массив отдельных символов. Срез может использоваться в выражениях везде, где может использоваться строка. Нумерация символов в срезах строк ведется от единицы.
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var s := 'Параграф';
 +
s[:5].Println; // Пара
 +
s[5:].Println; // граф
 +
s[2:5].Println; // ара
 +
s[3::2].Println; // рга
 +
s[8::-2].Print // фраа
 +
</syntaxhighlight>
 +
 +
Имеется также расширение .Slice, позволяющее получать срезы.
 +
Нумерация символов здесь ведется от нуля.
 +
* s.Slice(f, h) – возвращает срез строки s, начиная с позиции f и выбирая символы с шагом h;
 +
* s.Slice(f, h, k) – возвращает срез строки s длины не более k, начиная с позиции f и выбирая символы с шагом h;
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var s := 'Параграф';
 +
s.Slice(0, 1, 4).Println; // Пара
 +
s.Slice(4, 1).Println; // граф
 +
</syntaxhighlight>
 +
 +
== Модификация строки ==
 +
=== Смена регистра символов  ===
 +
Как и в случае с отдельными символами, в строке можно изменять регистр всех символов или их части. Используются расширения, возвращающие новую строку.
 +
* расширение s.ToLower возвращает строку s, приведенную к нижнему регистру;
 +
* расширение s.ToUpper возвращает строку s, приведенную к верхнему регистру.
 +
 +
=== Удаление символов в начале и конце  ===
 +
Наиболее популярным при обработке строк является удаление пробелов перед первым непробельным символом (левые, или лидирующие пробелы) и после последнего непробельного символа (правые, или завершающие пробелы).
 +
* s.TrimStart – метод, возвращающий исходную строку s с удаленными лидирующими пробелами;
 +
* s.TrimEnd – метод, возвращающий исходную строку s с удаленными завершающими пробелами;
 +
* s.Trim – метод, возвращающий исходную строку s с удаленными лидирующими и завершающими пробелами
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var P: procedure(s: string) := s -> Println('|' + s + '|');
 +
var s := '  Маша  ела  кашу  ';
 +
P(s); // '|' - чтобы видеть пробелы в начале и конце
 +
P(s.TrimStart);
 +
P(s.TrimEnd);
 +
P(s.Trim);
 +
</syntaxhighlight>
 +
|  Маша  ела  кашу  |
 +
|Маша  ела  кашу  |
 +
|  Маша  ела  кашу|
 +
|Маша  ела  кашу|
 +
 +
Кроме пробела имеются и другие непечатаемые (пробельные) символы, поэтому встречаются задачи и на удаление всех таких символов. Для этого нужно указать в качестве аргумента удаляемые символы, разделяя их запятыми или использовать массив символов. Не забывайте, что в этом случае пробельные символы тоже должны быть указаны, если они могут быть нежелательными.
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var s := ' .., + Это нужно! . , .,++ ';
 +
s.Trim(' ', '.', ',', '+').Println;
 +
var d := |' ', '.', ',', '+'|;
 +
s.Trim(d).Print;
 +
</syntaxhighlight>
 +
Это нужно!
 +
Это нужно!
 +
 +
== Удаление подстрок ==
 +
=== Удаление срезами ===
 +
Удалить подстроку в позициях символов [i; j] можно при помощи срезов. Для этого нужно взять символы c от начала строки и до номера i, не включая его и соединить с символами, номера которых начинаются после j и следуют до конца строки. Такую операцию для строки с именем s можно записать как
 +
<syntaxhighlight lang="pascal" line>
 +
s := s[:i] + s[j + 1:];
 +
</syntaxhighlight>
 +
 +
=== Удаление функцией Delete ===
 +
Можно воспользоваться процедурой Delete(s, from, k), удаляющей из строки s подстроку длиной k символов, начиная с позиции from. Если удаляемых символов окажется меньше k, будут удалены символы до конца строки. Эта процедура сохранена в целях совместимости с базовым Паскалем.
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var s := 'У Вани машина, у Наташи - мяч';
 +
//        12345678901234567890123456789
 +
//        -------                -----
 +
Delete(s, 8, 17);
 +
s.Print;
 +
</syntaxhighlight>
 +
=== Удаление методом Remove 1 ===
 +
Расширение s.Remove(from, k) возвращает строку, полученную удалением из строки s подстроки длиной k символов, начиная с позиции from. Это расширение класса string, поэтому индексирование ведется от нуля. Если удалить k символов окажется невозможно, выполнение программы завершится аварийно.
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var s := 'У Вани машина, у Наташи - мяч';
 +
//        01234567890123456789012345678
 +
//        -------                -----
 +
s.Remove(7, 17).Print
 +
</syntaxhighlight>
 +
 +
=== Удаление методом Remove 2 ===
 +
Расширение s.Remove(ss) умеет делать еще один вид удаления – возвращать строку, полученную путем удаления из строки s всех вхождений всех подстрок, определенных параметром ss. В качестве этого параметра можно задать массив подстрок, либо перечислить подстроки через запятую.
 +
<syntaxhighlight lang="pascal" line>
 +
##
 +
var s := 'У Вани машина, у Наташи - мяч';
 +
s.Remove('машина', 'мяч', '-').Print
 +
// У Вани , у Наташи
 +
</syntaxhighlight>

Версия 15:52, 19 апреля 2023

Pascal ABC.NET выбор школьника - Часть 3

Символы (char)

Данные символьного типа имеют тип char и занимают в памяти два байта. Используется кодировка стандарта Unicode. В тексте программы символьная константа (так называемый литерал) всегда заключается в одинарные кавычки.

 1 var c1, p135, rz: char; // три переменные
 2 var Символ1: char; // одна переменная
 3 var s: sequence of char; // последовательность символов;
 4 var ca: array[1..35] of char; // статический массив символов
 5 var ar: array of char; // динамический массив символов
 6 var m: array[,] of char; // матрица символов
 7 
 8 var a: char := 'a'; // тип указан явно
 9 var b:= 'b'; // автовыведение типа
10 var kt:= ('A', 'B', 'C'); // кортеж из трех символов

Перевод символа в его код и обратно

Символ в код

  • Ord(c) – код символа c в Unicode (тип word длиной 2 байта);
  • char.Code – то же, точечная нотация;

Код в символ

  • Chr(код) – символ с указанным кодом Unicode;
  • #код – символ с указанным кодом Unicode; принимает только

литерал;

Принадлежность символа к группе

Является ли символ буквой?

c.IsLetter

Расширение c.IsLetter возвращает True, если символ c принадлежит к группе букв и False в противном случае.

Является ли символ цифрой?

c.IsDigit

Расширение c.IsDigit возвращает True, если символ c принадлежит к группе цифр и False в противном случае.

Является ли символ пробельным?

Пробельные символы – термин, пришедший из типографской практики. Пробел – это пустое место, интервал между символами. Пробельными в типографском и издательском деле называют непечатаемые (и неотображаемые) символы. Символы с десятичными кодами 9..13 относятся к так называемым управляющим символам – раньше они управляли внешними устройствами, такими как механический принтер. Символ с кодом 32 – это пробел.
char.IsWhiteSpace(c)

Статический метод char.IsWhiteSpace(c) возвращает True, если символ c принадлежит к группе пробельных символов и False в противном случае.

Является ли символ знаком препинания?

char.IsPunctuation(c)

Статический метод char.IsPunctuation(c) возвращает True, если символ c принадлежит к группе знаков пунктуации (разделителям) и False в противном случае.

Принадлежит ли буква к верхнему регистру?

c.IsUpper

Расширение c.IsUpper возвращает True, если символ c принадлежит к буквенным символам верхнего регистра (прописным) и False в противном случае. Если символ не является буквой, всегда возвращается False.

Принадлежит ли буква к нижнему регистру?

c.IsLower

Расширение c.IsLower возвращает True, если символ c принадлежит к буквенным символам нижнего регистра (строчным) и False в противном случае. Если символ не является буквой, всегда возвращается False.

Принадлежит ли символ интервалу?

c in c1..c2

Конструкция c in c1..c2 вернет True, если символ c принадлежит группе символов от с1 до с2 включительно и False в противном случае.

Операции преобразования символов

Смена регистра буквенного символа

  • c.ToUpper – расширение возвращает буквенный символ c, приведенный к верхнему регистру, если он принадлежит к нижнему регистру. В противном случае символ возвращается без изменения;
  • UpCase(c) – функция, делающая то же самое;
  • c.ToLower – расширение возвращает буквенный символ c, приведенный к нижнему регистру, если он принадлежит к верхнему регистру. В противном случае символ возвращается без изменения;
  • LowCase(c) – функция, делающая то же самое

Преобразование цифрового символа в число

c.ToDigit

Расширение c.ToDigit возвращает буквенный символ c, преобразованный к изображаемому им целому неотрицательному однозначному числу типа integer. Если символ не является цифрой при выполнении программы будет выдано сообщение «Ошибка времени выполнения: not a Digit» и программа завершится аварийно.

Получение символа, соседнего с указанным

  • c.Pred – расширение возвращает буквенный символ, код которого в кодовой таблице предшествует коду символа c;
  • Pred(c) – функция, делающая то же самое;
  • c.Succ – расширение возвращает буквенный символ, код которого следует за кодом символа c;
  • Succ(c) – функция, делающая то же самое.

Смещение по символам кодовой таблицы

  • Dec(c) – процедура, заменяющая значение переменной, содержащей символ c на символ, предшествующий ему. Ведь это обычная

операция декремента, только для символа;

  • Dec(c, n) – процедура, заменяющая значение переменной c, содержащей символ c на символ, находящийся в кодовой таблице на n

позиций раньше. Тоже декремент;

  • Inc(c) – процедура, заменяющая значение переменной, содержащей символ c на символ, следующий за ним. Это инкремент.
  • Inc(c, n) – процедура, заменяющая значение переменной, содержащей символ c на символ, находящийся в кодовой таблице на n

позиций дальше. И это инкремент.

Ввод символов

Функции, осуществляющие ввод символьных данных с приглашением:

1 var c1 := ReadlnChar('ТекстПриглашения'); // ввод одного символа
2 var c2 := ReadlnChar2('ТекстПриглашения'); // ввод двух символов
3 var c3 := ReadlnChar3('ТекстПриглашения'); // ввод трех символов
4 var c4 := ReadlnChar4('ТекстПриглашения'); // ввод четырех символов

Вывод символов

С выводом все просто: используются уже знакомые процедуры Write, Writeln, Print, Println, а также расширения .Print и .Println. Имеется лишь oдна особенность вывода символов при помощи расширений: разделителем по умолчанию является не пробел, а пустой символ.

Строки

В PascalABC.NET строка – это последовательность символов практически неограниченной длины (на самом деле, строка не может занимать в памяти больше 2.1 Гбайт), принадлежащая некоторому алфавиту.

Символы в строке нумеруются от единицы (Эта особенность унаследована от языка Turbo Pascal) и чтобы обратиться к символу с номером k в строке s нужно написать s[k].

Чтобы символы строк нумеровались с 0 как и элементы динамических массивов необходимо в начале файла написать директиву компилятора.

{$ZeroBasedStrings}

Имеются два типа строк. Первый тип – строки длиной не превышающей 255 символов, унаследованные от языка Turbo Pascal. Они именуются короткими строками». При описании короткой строки после ключевого слова string в квадратных скобках указывается ее максимальная длина. Короткие строки оставлены в языке лишь для совместимости со старыми программами. Второй, основной тип строк – современные строки; при их описании длина не указывается. Мы будем рассматривать именно такие строки.

1 var st, s1, p18: string; // три строки
2 var s1: string; // одна строка
3 var sos: sequence of string; // последовательность строк
4 var ar: array of string; // динамический массив строк
5 var sh1: string[27]; // короткая строка, максимум 27 символов
6 // Описание строк можно соединять с инициализацией:
7 var s1: string := 'Это строка'; // тип указан явно
8 var s2 := '*** И это строка ***'; // автовыведение типа
9 var kt := ('Это', 'тоже', 'строка'); // кортеж из трех строк

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

Длина строки

Текущую длину строки, т.е. количество символов в ней, можно определить следующим образом:

  • s.Length – свойство, возвращает длину строки s
  • Length(s) – функция, делающая то же самое

Нумерация символов в строке от 0 или от 1

Если вы не используете директиву компилятора {$ZeroBasedStrings} для нумерации символов строк с 0, то важно иметь ввиду это различие.

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

Запомнить это проще всего визуально. Если в коде программы строка s используется в записи вида string.Метод(s) или s.Метод, она считается индексированной от нуля. Если «точки» нет, то строка считается индексированной от единицы.

Например в этом коде находится и выводится индекс символа '5' в строке s. Поскольку s.IndexOf – метод класса string, считается, что индексы идут от нуля и выводится значение 4. Функция Pos не относится к классу string, поэтому выводится порядковый номер, равный 5.

1 ##
2 var s := '123456789';
3 Print(s.IndexOf('5'), Pos('5', s))

Ввод строк

Строки можно вводить как классическим оператором

Readln

так и доступными в современном Паскале функциями.

1 Begin
2   var s1 := ReadString('Введите строку');
3   var s2 := ReadString2('Введите 2 строки');
4   var s3 := ReadString3('Введите 3 строки');
5   var s4 := ReadString4('Введите 4 строки');
6 end.

Вывод строк

Write(ln) + Print(ln)

Выводить строки можно любыми средствами, которые использовались для вывода других типов данных: Print и Println, Write и Writeln, а также при помощи расширений .Print и .Println. Расширения рассматривают строку, как последовательность отдельных символов, но выводят эти символы не через пробел, как для других типов данных, а через пустой символ. Тем не менее, расширения .Print и .Println могут принимать в качестве параметра строку-разделитель, что иллюстрирует следующая простая программа.

1 ##
2 'Тестовая строка'.Println;
3 'Тестовая строка'.Println(' ');
4 'Тестовая строка'.Println('*');
5 'Тестовая строка'.Println(' = ');
Тестовая строка
Т е с т о в а я с т р о к а
Т*е*с*т*о*в*а*я* *с*т*р*о*к*а
Т = е = с = т = о = в = а = я = = с = т = р = о = к = а

Арифметические операции со строками

Сложение / Конкатенация

Операция сложения «+», примененная к строкам, объединяет их в общую строку. Если же одним из операндов является значение числового выражения, а вторым – строка, то числовое значение предварительно преобразуется к строковому виду, а потом выполняется объединение.

Умножение

В операции умножения «*» один операнд должен быть строкой, второй - целочисленным выражением. В результате строка соединяется сама с собой указанное значением выражения количество раз, давая новую строку. В одном операторе можно записывать и больше одного сложения и/или умножения.

1 ## Println('--- 25 + 3 * 8 =' + (25 + 3 * 8) + ' ---')
--- 25 + 3 * 8 = 49 ---

Можно «склеить» в строку и повторенный несколько раз отдельный символ, например

1 var s := 30 * '+';

Управление длинной строки

Строку можно усечь или удлинить, изменяя ее длину. Это можно сделать при помощи процедуры SetLength (помните, та самая, управляющая длиной массива). Удлиняемая строка дополняется справа пробелами до нужной длины.

1 begin
2  var P: string -> () := s -> Println('|' + s + '|');
3  var s := 'Маша ела кашу';
4  P(s); // '|' - чтобы видеть пробелы в начале и конце
5  SetLength(s, s.Length - 4);
6  P(s);
7  SetLength(s, s.Length + 6);
8  P(s)
9 end.
|Маша ела кашу|
|Маша ела |
|Маша ела       |

Сравнение строк

Содержимое строк, даже если их длина различна, можно сравнивать между собой. Строки сравниваются посимвольно слева направо до первого несовпадения кодов символов, либо до окончания одной или обеих строк. Для строк определены результаты всех шести операций сравнения: <, <=, =, <>, >, >=. Большим считается тот символ, код Unicode которого больше (говорят, что символы сравниваются лексикографически). Если все символы более короткой строки совпали с символами более длинной, то большей строкой считается более длинная строка.

1 ##
2 Println('Кошка' > 'Мышка'); // False, 'К' < 'М'
3 Println('12345' > '1234'); // True, строка 1 длиннее
4 Println('ЛЕН' > 'ЛЁН'); // True, 'Ё' в Unicode идет перед 'А'
5 Println('лен' > 'лён'); // False, 'ё' в Unicode после 'я'
6 Println('Папа' <= 'мама'); // True, 'П' < 'м'
7 Println('Пoдвох' = 'Подвох') // False, первая 'о' - латинская

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

  • цифры '0'..'9' имеют десятичные коды #48..#56;
  • латинские буквы 'A'..'Z' имеют десятичные коды #65..#90;
  • латинские буквы 'a'..'z' имеют десятичные коды #97..#122;
  • буква 'Ё' имеет десятичный код #1025;
  • буквы кириллицы 'А'..'Я' (кроме Ё) имеют десятичные коды
  1. 1040..#1071;
  • буквы кириллицы 'а'..'я' (кроме ё) имеют десятичные коды
  1. 1072..#1103;
  • буква 'ё' имеет десятичный код #1105.

Выделение подстроки

Подстрока – это часть строки, полученная путем выборки некоторых ее символов, следующих подряд.

  • расширение s.Left(k) возвращает k левых символов строки s;
  • расширение s.Right(k) возвращает k правых символов строки s.

Для получения подстроки удобно использовать срезы. Легче запоминается, короче запись.

Срезы строк

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

1 ##
2 var s := 'Параграф';
3 s[:5].Println; // Пара
4 s[5:].Println; // граф
5 s[2:5].Println; // ара
6 s[3::2].Println; // рга
7 s[8::-2].Print // фраа

Имеется также расширение .Slice, позволяющее получать срезы.

Нумерация символов здесь ведется от нуля.
  • s.Slice(f, h) – возвращает срез строки s, начиная с позиции f и выбирая символы с шагом h;
  • s.Slice(f, h, k) – возвращает срез строки s длины не более k, начиная с позиции f и выбирая символы с шагом h;
1 ##
2 var s := 'Параграф';
3 s.Slice(0, 1, 4).Println; // Пара
4 s.Slice(4, 1).Println; // граф

Модификация строки

Смена регистра символов

Как и в случае с отдельными символами, в строке можно изменять регистр всех символов или их части. Используются расширения, возвращающие новую строку.

  • расширение s.ToLower возвращает строку s, приведенную к нижнему регистру;
  • расширение s.ToUpper возвращает строку s, приведенную к верхнему регистру.

Удаление символов в начале и конце

Наиболее популярным при обработке строк является удаление пробелов перед первым непробельным символом (левые, или лидирующие пробелы) и после последнего непробельного символа (правые, или завершающие пробелы).

  • s.TrimStart – метод, возвращающий исходную строку s с удаленными лидирующими пробелами;
  • s.TrimEnd – метод, возвращающий исходную строку s с удаленными завершающими пробелами;
  • s.Trim – метод, возвращающий исходную строку s с удаленными лидирующими и завершающими пробелами
1 ##
2 var P: procedure(s: string) := s -> Println('|' + s + '|');
3 var s := '   Маша   ела   кашу   ';
4 P(s); // '|' - чтобы видеть пробелы в начале и конце
5 P(s.TrimStart);
6 P(s.TrimEnd);
7 P(s.Trim);
|   Маша   ела   кашу   | 
|Маша   ела   кашу   | 
|   Маша   ела   кашу| 
|Маша   ела   кашу|

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

1 ##
2 var s := ' .., + Это нужно! . , .,++ ';
3 s.Trim(' ', '.', ',', '+').Println;
4 var d := |' ', '.', ',', '+'|;
5 s.Trim(d).Print;
Это нужно!
Это нужно!

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

Удаление срезами

Удалить подстроку в позициях символов [i; j] можно при помощи срезов. Для этого нужно взять символы c от начала строки и до номера i, не включая его и соединить с символами, номера которых начинаются после j и следуют до конца строки. Такую операцию для строки с именем s можно записать как

1 s := s[:i] + s[j + 1:];

Удаление функцией Delete

Можно воспользоваться процедурой Delete(s, from, k), удаляющей из строки s подстроку длиной k символов, начиная с позиции from. Если удаляемых символов окажется меньше k, будут удалены символы до конца строки. Эта процедура сохранена в целях совместимости с базовым Паскалем.

1 ##
2 var s := 'У Вани машина, у Наташи - мяч';
3 //        12345678901234567890123456789
4 //        -------                 -----
5 Delete(s, 8, 17);
6 s.Print;

Удаление методом Remove 1

Расширение s.Remove(from, k) возвращает строку, полученную удалением из строки s подстроки длиной k символов, начиная с позиции from. Это расширение класса string, поэтому индексирование ведется от нуля. Если удалить k символов окажется невозможно, выполнение программы завершится аварийно.

1 ##
2 var s := 'У Вани машина, у Наташи - мяч';
3 //        01234567890123456789012345678
4 //        -------                 -----
5 s.Remove(7, 17).Print

Удаление методом Remove 2

Расширение s.Remove(ss) умеет делать еще один вид удаления – возвращать строку, полученную путем удаления из строки s всех вхождений всех подстрок, определенных параметром ss. В качестве этого параметра можно задать массив подстрок, либо перечислить подстроки через запятую.

1 ##
2 var s := 'У Вани машина, у Наташи - мяч';
3 s.Remove('машина', 'мяч', '-').Print
4 // У Вани , у Наташи