, : arrays2, : Top


10 Символы и строки

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

10.1 Символьный тип char

Любой текст состоит из символов. Для хранения одного символа предназначен тип данных char. Переменную типа char можно рассматривать двояко: как целое число, занимающее 1 байт и способное принимать значения от 0 до 255 (тип unsigned char) или от -128 до 127 (тип signed char) и как один текстовый символ. Сам же тип char может оказаться как знаковым, так и беззнаковым, в зависимости от операционной системы и компилятора. Поэтому использовать тип char не рекомендуется, лучше явно указывать будет ли он знаковым (signed) или беззнаковым (unsigned).

Как и целые числа, данные типа char можно складывать, вычитать, умножать, делить, а можно выводить на экран в виде одного символа. Именно это и происходит при выводе символа через объект cout. Если же нужно вывести числовое значение символа (также называемый ASCII-кодом), то значение символа необходимо преобразовать к типу int. Например:

     #include<iostream>
     using namespace std;
     int main()
     {
         unsigned char c='A'; // Константы char заключаются в одинарные кавычки
         cout<<c<<" "<<(int)c<<endl;
         c=126;      // char можно присвоить и числовое значение
         cout<<c<<" "<<(int)c<<endl;
         return 0;
     }

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

Организовать последовательное посимвольное считывание всего входного потока можно при помощи цикла while:

     #include<iostream>
     using namespace std;
     int main()
     {
         unsigned char c;
         while(cin>>c) // Цикл пока считывание успешно
         {  // Делаем необходимые действия
         }
         return 0;
     }

В этом примере программа будет посимвольно считывать входной поток (по умолчанию — ввод с клавиатуры), пока не встретит признак конца файла. Для того, чтобы сообщить программе о завершении файла при вводе с клавиатуры необходимо нажать клавиши Ctrl-d в системе Linux и Ctrl-z в системе Windows.

Эта программа при считывании данных будет игнорировать символы–разделители: пробелы, символы новой строки и табуляции. Если нужно, чтобы в переменную c считывались все символы, в том числе и разделители, то необходимо для потока ввода cin установить манипулятор noskipws при помощи инструкции cin>>noskipws;.

Строки в языке C++

Текстовую строку можно представить, как массив символов типа char, но в языке C++ для хранения текстовых строк был создан более удобный тип string. По сути, тип данных string и является массивом символов, например, если мы объявили переменную S как string S, а затем присвоили ей значение "школа" (текстовые строки заключаются в двойные кавычки), то мы можем обращаться к отдельным символам строки S, представляя S, как массив символов, например, S[0]=='ш', S[1]=='к' и т.д. Для того, чтобы узнать длину строки используется метод length(), вызываемый в виде S.length().

Строковые данные можно считывать с клавиатуры, выводить на экран, присвавать переменным типа string. Также строки можно складывать друг с другом: например, при сложении строк "Hello, " и "world!" получится строка "Hello, world!". Такая операция над строками называется конкатенацией.

Основные приемы работы с объектами string проиллюстрированы в программе:

     string S, S1, S2;           // Объявление трех строк
     cout<<"Как вас зовут? ";
     cin>>S1;                    // Считали строку S1
     S2="Привет, ";              // Присвоили строке значение
     S=S2+S1;                    // Использование конкатенации
     cout<<S<<endl;              // Вывод строки на экран
     cout<<S.length();           // Длина строки S

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

     string S1, S2, S3; // объявили 3 строки
     cin>>S1>>S2>>S3;

ввести текст ‘Мама мыла раму’ (с произвольным количеством пробелов между словами), то в массив S1 будет записана строка "Мама", в S2 "мыла", в S3 "раму".

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

     string s;
     while(cin>>s) // Цикл пока считывание успешно
     {             // Делаем необходимые действия
     }

Если нужно считать строку со всеми пробелами, то необходимо использовать функцию getline следующим образом:

     string S;
     getline(cin,S);

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

     string s;
     while ( getline(cin,S) ) // Цикл пока считывание успешно
     {                        // Делаем необходимые действия
     }

Упражнения

Если в упражнении сказано "дана строка", то ее можно считать при помощи инструкции вида cin>>S или при помощи функции getline. Если сказано, что дана строка, содержащая пробелы, то ее необходимо считывать при помощи функции getline.

  1. (Без тестирующей системы) Выведите на экран все возможные символы с ASCII-кодами от 32 до 255 (символы с кодами до 32 являются служебными и их вывод на экран может привести к забавным последствиям) и их ASCII-коды. Формат вывода: сначала ASCII-код, затем символ, например,
              32
              33 !
              34 "
              35 #
    
  2. (A) Напишите функцию bool IsDigit(unsigned char c), определяющую, является ли данный символ цифрой или нет. Напишите программу, которая получает на вход один символ и выводит строку yes, если символ является цифрой и строку no, в противном случае.
  3. (B) Программа получает на вход один символ. Если этот символ является строчной буквой латинского алфавита (то есть буквой от a до z), выведите вместо него аналогичную заглавную букву, иначе выведите тот же самый символ (такая операция называется "перевод в верхний регистр"). Для этого сделайте функцию unsigned char ToUpper(unsigned char c), которая переводит данный символ в верхний регистр.
  4. (C) Измените регистр символа: если он был латинской буквой: сделайте его заглавным, если он был строчной буквой и наоборот. Для этого напишите отдельную функцию, меняющую регистр символа.
  5. (D) Даны две строки. Определите, совпадают ли они сравнив их посимвольно. Напишите для этого функцию bool Compare(string S1, string S2).

    Вход: две строки. Выход: слово yes, если строки совпадают, слово no в противном случае.

  6. (E) Дана строка, содержащая пробелы. Найдите, сколько в нем слов (слово – это последовательность непробельных символов, слова разделены одним пробелом, первый и последний символ строки – не пробел).

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

  7. (F) Дана строка, содержащая пробелы. Найдите в ней самое длинное слово, выведите на экран это слово и его длину.

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

  8. (G) По данной строке, определите, является ли она палиндромом (то есть можно ли прочесть ее наоборот, как, например, слово ‘топот’).

    Вход: одна строка без пробелов. Выход: yes, если слово является палиндромом, no в противном случае.

  9. (H) Дана строка. Известно, что она содержит ровно две одинаковые буквы. Найдите эти буквы.

    Вход: одна строка. Выход: одна буква, которая встречается в строке дважды.

  10. (I) Даны две строки. Определите, является ли первая строка подстрокой второй строки.

    Вход: две строки. Выход: слово yes, если первая строка является подстрокой второй строки, или слово no в противном случае.

  11. (J) Капитан Флинт зарыл клад на Острове сокровищ. Он оставил описание, как найти клад. Описание состоит из строк вида: "North 5", где первое слово – одно из "North", "South", "East", "West", а второе число – количество шагов, необходимое пройти в этом направлении.

    Напишите программу, которая по описанию пути к кладу определяет точные координаты клада, считая, что начало координат находится в начале пути, ось OX направлена на восток, ось OY – на север.

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

    Например, при вводе

              North 5
              East 3
              South 1
    

    программа должна вывести координаты 3 4.

  12. (K) Дана строка, содержащая пробелы. Проверьте, является ли она палиндромом без учета пробелов (например, ‘аргентина манит негра’).

    Вход: одна строка, содержащая пробелы. Подряд может идти произвольное число пробелов. Выход: yes, если данная строка является палиндромом и no в противном случае.