4.12 – Знакомство с std::string
Самая первая написанная вами программа на C++, вероятно, выглядела примерно так:
Так что точно такое " Hello, world! "? " Hello, world! " представляет собой набор последовательных символов, называемый строкой. В C++ мы используем строки для представления текста, такого как имена, адреса, слова и предложения. Строковые литералы (например, " Hello, world!\n ") помещаются в двойные кавычки, чтобы идентифицировать их как строки.
Поскольку в программах строки обычно используются, большинство современных языков программирования включают в себя базовый строковый тип данных. В C++ строки не являются базовым типом (на самом деле они являются составным типом и определены в стандартной библиотеке C++, а не как часть ядра языка). Но строки достаточно просты и полезны, поэтому мы представим их здесь, а не будем дожидаться главы о составных типах (глава 8).
std::string
Чтобы использовать строки в C++, нам сначала нужно включить через #include заголовочный файл <string> , чтобы ввести объявления для std::string . Как только это будет сделано, мы сможем определить переменные типа std::string .
Вы можете инициализировать или присваивать значения строкам, как и обычным переменным, что и следовало ожидать:
Обратите внимание, что строки также могут содержать числа:
В строковой форме числа обрабатываются как текст, а не как числа, и поэтому ими нельзя манипулировать как числами (например, вы не можете их умножать). C++ не будет автоматически преобразовывать строковые числа в целочисленные значения или значения с плавающей запятой.
Вывод строк
Строки можно выводить, как и ожидалось, с помощью std::cout :
Эта программа печатает:
Пустые строки ничего не напечатают:
Эта программа напечатает:
Ввод строк с помощью std::cin
Использование строк с std::cin может преподнести сюрпризы! Рассмотрим следующий пример:
Ниже показаны результаты пробного запуска этой программы:
Хммм, это неправильно! Что случилось? Оказывается, что при использовании operator>> для извлечения из cin строки operator>> возвращает только символы до первого попавшегося пробела. Все остальные символы остаются внутри std::cin в ожидании следующего извлечения.
Поэтому, когда мы использовали operator>> для извлечения строки в переменную name , было извлечено только " John ", оставив " Doe " внутри std::cin . Когда мы снова использовали operator>> для получения переменной age , он извлек " Doe " вместо того, чтобы ждать, пока мы введем возраст. На этом программа заканчивается.
Для ввода текста используйте std::getline()
Чтобы прочитать всю строку входных данных в переменную строки, лучше вместо этого использовать функцию std::getline() . std::getline() принимает два параметра: первый – это std::cin , а второй – ваша строковая переменная.
Вот та же программа, что и выше, с использованием std::getline() :
Теперь наша программа работает как и ожидалось:
Что еще за std::ws ?
В уроке «4.8 – Числовые типы с плавающей точкой» мы обсудили манипуляторы вывода, которые позволяют нам изменять способ отображения выводимых значений. В том уроке мы использовали функцию манипулятора вывода std::setprecision() , чтобы изменить количество значащих цифр, отображаемых std::cout .
C++ также поддерживает манипуляторы ввода (определенные в заголовке iomanip ), которые изменяют способ приема входных данных. Манипулятор ввода std::ws говорит std::cin игнорировать любые начальные пробелы. Обратите внимание, что std::ws не является функцией.
Давайте разберемся, чем он полезен. Рассмотрим следующую программу:
Вот пример результата работы этой программы:
Данная программа сначала просит вас ввести 1 или 2 и ждет, когда вы это сделаете. Пока всё хорошо. Затем она просит вас ввести свое имя. Однако на самом деле она не будет ждать, пока вы введете свое имя! Вместо этого она печатает строку " Hello ", а затем завершит работу. Что случилось?
Оказывается, когда вы вводите значение с помощью operator>> , std::cin не только захватывает значение, но также захватывает символ новой строки (' \n '), который появляется, когда вы нажимаете клавишу Enter . Итак, когда мы набираем 2 и нажимаем Enter , std::cin получает строку " 2\n ". Затем он извлекает 2 в переменную choice , оставляя символ новой строки на потом. Затем, когда std::getline() переходит к чтению имени, он видит, что " \n " уже находится в потоке, и полагает, что мы, должно быть, ввели пустую строку! Это определенно не то, что было задумано.
Мы можем изменить приведенную выше программу, чтобы использовать манипулятор ввода std::ws , чтобы указать std::getline() игнорировать любые начальные пробельные символы:
Теперь эта программа будет работать так, как задумано.
Лучшая практика
Если для чтения строк используется функция std::getline , используйте манипулятор ввода std::ws , чтобы игнорировать начальные пробелы.
Ключевые выводы
Использование оператора извлечения ( >> ) с std::cin игнорирует начальные пробелы.
std::getline не игнорирует начальные пробелы, если вы не используете манипулятор ввода std::ws .
Длина строки
Если мы хотим знать, сколько символов находится в std::string , мы можем спросить переменную std::string о ее длине. Синтаксис для этого отличается от того, что вы видели раньше, но он довольно прост:
Обратите внимание, что вместо того, чтобы запрашивать длину строки как length(myName) , мы говорим myName.length() . Функция length() не является обычной автономной функцией – это особый тип функции, которая принадлежит std::string и называется функцией-членом. Позже мы расскажем о функциях-членах, в том числе о том, как написать свои собственные.
Заключение
std::string сложен и использует многие языковые функции, которые мы еще не рассмотрели. К счастью, вам не нужно разбираться в этих сложностях, чтобы использовать std::string для простых задач, таких как простейший ввод и вывод строк. Мы рекомендуем вам начать экспериментировать со строками прямо сейчас, а дополнительные возможности строк мы рассмотрим позже.
Небольшой тест
Вопрос 1
Напишите программу, которая просит пользователя ввести свое полное имя и возраст. В качестве вывода сообщите пользователю, сколько лет он прожил для каждой буквы в своем имени (для простоты считайте пробелы как букву).
string: шаблонный строковый класс STL
Приветствую вас коллеги – программисты. В данной статье я хочу познакомить Вас с шаблонным классом string . Который призван облегчить жизнь программистам. Кто не знает, string – это STL’евский класс основанный на шаблонах, который входит в стандартную библиотеку C++ . Для использования данного класса в ваших приложениях, нужно подключить директиву <string> .
Вначале посмотрим на простой пример применения, возможности и внутреннее представление класса, а в конце статьи реализуем собственный класс string !
Если вы раньше уже имели дело со стандартным строковым типом, то могли заметить, что его применение опасно возникновением ошибок и не так удобно как хотелось бы из-за того, что реализован он на более низком уровне. Так вот, использование класса string, здорово облегчит вам процесс использования строковых типов в ваших приложениях.
Давайте рассмотрим простейший пример использования:
Здесь создается экземпляр класса под именем str , далее пользователя просят представиться, при помощи std::getline данные записываются из потока cin непосредственно в нашу переменную str . Думаю далее всё очевидно.
Как видите использование класса string , не сложнее, а поверьте даже намного легче чем обычного строкового типа char* .
Итак не забывайте что, для того чтобы использовать объекты класса string , необходимо включить соответствующий заголовочный файл:
Далее для демонстрации работы методов и вспомогательных функций будем использовать следующий объект:
Чтобы узнать длину строки, можно воспользоваться функцией-членом size() , или length() , которые, как и ожидается, возвращают саму длину (длина не включает завершающий нулевой символ).
А как же узнать, пуста ли строка? Вы скажете у нас же есть метод возвращающий длину, следовательно можно применить следующую конструкцию:
Однако и для таких случаев имеется специальный метод empty() , возвращающий true для пустой строки и false для непустой:
Как мы можем узнать, совпадают ли строки? Воспользуемся оператором сравнения == :
А как же можно скопировать одну строку в другую? Это можно реализовать с помощью обычной операции присваивания = :
Возможно вы спросите почему я не сделал так?:
Эта запись эквивалентна пред ыдущей, за исключением того, что в предыдущем коде мы использовали оператор присваивания, а этом случае работает конструктор копирования.
Для конкатенации строк используется операция сложения + или операция сложения с присваиванием += . Рассмотрим следующий код:
Мы можем получить строку «HelloWorld» , состоящую из конкатенации str1 и str2 , таким образом:
В результате в строке str3 будет хранится следующее: «HelloWorld» .
Так же подобного результата, мы можем добиться и другим способом:
Здесь мы создаем строку str3 инициализируя её содержимым str1 , и далее при помощи оператора += в конец str3 добавляем str2 . Результат будет таким как и в предыдущем примере.
Операция сложения может конкатенировать (соединять, присоединять) экземпляры (объекты) класса std::string не только между собой, но и со строками встроенного типа. Такой код будет вполне работоспособным:
Надеюсь как вы уже догадались в результате в строке str2 , будет хранится «HelloWorld!»
Ещё одна весьма полезная функция это: c_str() .
Функция c_str() возвращает указатель на символьный массив, который содержит строку объекта стринг ( string ) в том виде, в котором она размещалась бы, во встроенном строковом типе. Например :
Чтобы обращаться к отдельным символам строки типа string , можно воспользоваться операцией взятия индекса ( [] ), или при помощи метода at(). Например :
Метод at() предлагает похожую схему доступа, за исключением того, что индекс предоставляется как аргумент функции:
В отличии от оператора [] , метод at() , обеспечивает проверку границ и генерирует исключение out_of_range , если вы пытаетесь получить несуществующий элемент.
Так же в классе string , имеется функция, которая возвращает строку, являющуюся подстрокой исходной строки, начиная с позиции pos и включая n символов, или до конца строки.
На самом деле std::string имеет намного больше методов и возможностей, чем было рассмотрено здесь, и если бы я решил описать хотя бы половину, то вся эта информация никак не поместилась бы в одну статью. Но основные моменты работы со стрингом мы рассмотрели и новичкам будет достаточно и этих знаний.
Полное представление класса string (конструкторы, перегруженные операции, методы, дополнительные функции, и т.д), можно посмотреть здесь: http://www.cplusplus.com/reference/string/basic_string Стандартный класс string основан на таком определении шаблона:
Здесь charT представляет тип, который хранится в строке. Параметр traits представляет класс, определяющий необходимые свойства, которыми должен обладать тип для представления строки.
Например метод length() , который возвращает длину строки, представленную в виде массива типа charT . Конец такого массива указан значением charT(0) , которое является обобщенной формой нулевого символа. Параметр Allocator представляет класс для управления распределением памяти под строку. Шаблон по умолчанию allocator<charT> использует операции new и delete стандартными способами.
Как и любой более-менее сложный пользовательский тип (класс), класс string определяет свои конструкторы. Да да не конструктор, а конструкторы. Их в нём 11.
Вот часть из них:
Думаю пока нет смысла приводить здесь полный листинг реализации класса string , так как данная статья рассчитана на начинающих программистов, и в ней я планирую скорее научить вас использовать string , нежели объяснять его внутреннее представление. Я привёл здесь определение шаблона и описание некоторых конструкторов, только чтобы показать вам, что это действительно класс. Который можете реализовать и вы (возможно не такой эффективный и гибкий).
Ну что же, настало время реализовать свой простенький класс string . Но перед этим, не забывайте, что класс string обладает всеми возможностями стандартных типов. Если вы знакомы с классами, то наверное уже догадались, что для реализации таких возможностей, в классе должны быть перегружены многие операторы (в том числе ввода >> и вывода << ). Кроме того класс string содержит ещё множество полезных методов.
Итак, код нашего класса String выглядит так:
Безусловно этот класс, не может сравнится со стандартным, но всё же он вполне работоспособный и его также можно использовать в своих приложениях. Ну вот и всё, что я хотел рассказать вам в этой статье, помните как я уже говорил, std::string , обладает намного большими возможностями, чем было рассмотрено в данной статье. По большому счёту, я не упоминал о многих (возможностях), таки из-за того, что эта статья рассчитанная прежде всего для новичков. Удачи в ваших начинаниях!
Работа со строками
Довольно большое количество задач, которые могут встретиться при разработке приложений, так или иначе связано с обработкой строк — парсинг веб-страниц, поиск в тексте, какие-то аналитические задачи, связанные с извлечением нужной информации из текста и т.д. Поэтому в этом плане работе со строками уделяется особое внимание.
В языке C# строковые значения представляет тип string , а вся функциональность работы с данным типом сосредоточена в классе System.String . Собственно string является псевдонимом для класса String. Объекты этого класса представляют текст как последовательность символов Unicode. Максимальный размер объекта String может составлять в памяти 2 ГБ, или около 1 миллиарда символов.
Создание строк
Создавать строки можно, как используя переменную типа string и присваивая ей значение, так и применяя один из конструкторов класса String:
Конструктор String имеет различное число версий. Так, вызов конструктора
6 раз повторит объект из первого параметра, то есть фактически создаст строку «aaaaaa».
Еще один конструктор принимает массив символов, из которых создается строка
Третий использованный выше в примере конструктор позволяет создать строку из части массива символов. Второй параметр передает начальный индекс, с которого извлкаются символы, а третий параметр указывает на количество символов:
Строка как набор символов
Так как строка хранит коллекцию символов, в ней определен индексатор для доступа к этим символам:
Применяя индексатор, мы можем обратиться к строке как к массиву символов и получить по индексу любой из ее символов:
Используя свойство Length , как и в обычном массиве, можно получить длину строки.
Перебор строк
Класс String реализует интерфейс IEnumerable, благодаря чему строку можно перебрать в цикле foreach как набор объектов char. Также можно с помощью других типов циклов перебрать строку, применяя обращение к символам по индексу:
Сравнение строк
В отличие от других классов строки сравниваются по значению их символов, а не по ссылкам:
Многострочные строки
Начиная с C# 11 с помощью трех пар двойных кавычек можно оформить многострочный текст, в том числе с применением интерполяции:
Основные методы строк
Основная функциональность класса String раскрывается через его методы, среди которых можно выделить следующие:
Compare : сравнивает две строки с учетом текущей культуры (локали) пользователя
CompareOrdinal : сравнивает две строки без учета локали
Contains : определяет, содержится ли подстрока в строке
Concat : соединяет строки
CopyTo : копирует часть строки, начиная с определенного индекса в массив
EndsWith : определяет, совпадает ли конец строки с подстрокой
Format : форматирует строку
IndexOf : находит индекс первого вхождения символа или подстроки в строке
Insert : вставляет в строку подстроку
Join : соединяет элементы массива строк
LastIndexOf : находит индекс последнего вхождения символа или подстроки в строке
Replace : замещает в строке символ или подстроку другим символом или подстрокой
String в языке С: определение, типы, методы и использование
String в С — это определенный тип данных, который , по сути , является последовательностью различных символов, заключенных в «кавычки». Такой тип данных используется для написания каких-либо текстовых сообщений: имя, адрес, слова, предложения и др.
После подключения заголовочного файл а с о «строками» в С можно работать как с обычными переменными. Например, их можно объявлять и присваивать им значения:
std:: string auto(“AUDI“); //создаем переменную «auto» и присваиваем ей строковое значение «AUDI»
name = “VAZ“; //присваиваем переменной «auto» строковое значение «VAZ»
String в С может принимать любые символы, даже числа. Но если вписать в «строку» число, то оно оста н ется строкой и выполнять с ним арифметические действия не получится. С не преобразует число , записанное в «string» , в целочисленный тип данных, чтобы с ним можно было взаимодействовать как с числом.
Работа со string в Си
Строки можно выводить при помощи «cout» или «cin». Например, как работает «cout»:
int main()
<
std::string name(“Владимир“);
std::count < < “Меня зовут“ < < name;
return 0;
>
В результате выполнения программы мы получим: «Меня зовут Владимир».
Как работает «cin»:
int main()
<
std::cout < < “Введите ваше полное имя: “;
std::string myName;
std::cin > > myName
std::cout < < “Введите ваш возраст: “;
std::string myAge;
std::cin > > myAge;
std::cout « “ Ваше имя “ < < myName < < “ и ваш возраст “ < < myAge;
>
Результатом работы такой программы будет:
Введите ваше полное имя: «Владимир Мономах»
Введите ваш возраст: Ваше имя Владимир и ваш возраст Мономах
Вышло как-то не очень. Почему так? Оператор «>>» и «сin» работают немного по-другому. Оператор «>>» извлекает символы из входного потока, только до первого пробела, а остальные данные хранятся в «cin», пока не будут еще раз извлечены. Мы хотели извлечь полное имя в переменную «myName» при помощи оператора «>>», однако вместо всего имени «Владимир Мономах» мы получили только «Владимир», а вторым извлечением получили «Мономах». Если бы у нас было третье извлечение, тогда у нас был бы извлечен возраст, допустим , «30». Из этой ситуации есть выход.
Если необходимо извлекать все данные из входного потока, включая пробелы, тогда необходимо использовать функцию «std::getline()», которая несет в себе 2 аргумента: «std::cin» и «string». Вот как это выглядит:
int main()
<
std::cout < < “Введите ваше полное имя: “;
std::string myName;
std::getline(std::cin, myName);
std::cout < < “Введите ваш возраст: “;
std::string myAge;
std::getline(std::cin, myAge);
std::cout « “ Ваше имя “ < < myName < < “ и ваш возраст “ < < myAge;
>
Результатом такой программы будет:
Введите ваше имя: Владимир Мономах
Введите ваш возраст: 30
Ваше имя Владимир Мономах и ваш возраст 30
При такой реализации все будет работать как надо.
С вводом и выводом string в Си мы разобрались, но с о строками можно выполнять и другие манипуляции.
String в Си — это не только текст
-
посимвольное сравнение при помощи операторов «==» или «!=»;
-
лексикографическое сравнение при помощи операторов «<», «>», «<=», «>=».
String в Си: методы
-
Функция «size()». При помощи этой функции можно узнать длину строки.
-
Функция «resize(n)». При помощи этой функции можно изменить длину строки, которая станет р а вняться «n».
-
Функция «clear()». Данная функция полностью очищает строку и делает ее пустой.
-
Функция «emp t y()». При помощи этой функции можно проверить string — является она пустой или нет.
-
Функция «push_back(c)». При помощи этой функции в конец строки добавляется символ «с».
-
Функция «append()». Эта функция способна добавить в конец строки не просто символ, а другую строку или фрагмент строки.
-
Функция «erase(pos, cont)». При помощи этой функции можно удалить символы, начиная с индекса, указанного в «pos». «Cont» используется, чтобы обозначить количество символов, которые нужно удалить ; если не указать этот аргумент, тогда удалятся все символы до конца строки.
-
Функция «substr(pos, cont)». При помощи этой функции можно извлечь подстроку из строки, начиная с индекса , указанного в «pos». «Сont» необходимо указать, если нужно извлечь определенное количество символов.
-
Функция «replace(pos, cont)». Эта функция заменяет строку, кусочек строки или отдельный символ в строке на необходимое значение.
-
Функция «find(str, pos)». При помощи этой функции можно искать вхождение одной строки в друг ую . Функция возвращает индекс первого символа в строке, где найдено вхождение.
Заключение
String в Си хоть и не являются встроенным типом данных, но очень многофункциональны и часто применяются в программировании. Поэтому при изучении Си или С++ обязательно нужно понимать , как можно взаимодействовать со строками или другими типами данных , — это является основой программирования на любом языке.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.