Содержание
- Уроки
- Программирование
- Строки и массивы символов
Строки
Строка (String), как понятно из названия, это совокупность символов. По сути строка это одномерный массив типа данных char, про массивы мы уже недавно говорили и вы должны понять, о чём идёт речь. Как и в случае с массивом символов, к каждому элементу строки можно обратиться при помощи квадратных скобок. Основным отличием строки от массива символов является тот факт, что строка – динамический массив, у которого не нужно указывать размер. Также строка является не просто типом данных, а объектом, объектом очень мощного класса String.
Давайте рассмотрим большой пример, из которого будет понятно, как объявить строку и как с ней работать, а также учтены некоторые тонкости:
Как вы могли заметить, строки можно объявлять большим количеством способов, а также буквально складывать строки, как числа, оператором +. Я уже говорил, что строки являются объектами класса String, и у этого класса есть огромное количество удобных методов по работе со строками, далее мы их все рассмотрим с некоторыми примерами. Но для начала запомните вот что: строки – очень тяжёлый инструмент, очень медленный и занимающий кучу памяти: уже просто само наличие строк (от одной и более) в прошивке занимает +5% Flash памяти, т.к. подключается сам “инструмент” – класс String. Для небольших проектов это не страшно, памяти всегда будет навалом.
Инструменты для String
Итак, методы для работы со строками. Как и все методы, они применяются к своим объектам (к строкам) через точку. В рассмотренных ниже примерах строка называется myString.
myString.charAt(index);
Возвращает элемент строки myString под номером index. Аналог – myString[index];
myString.setCharAt(index, val);
Записывает в строку myString символ val на позицию index. Аналог – myString[index] = val;
myString.concat(value);
Присоединяет value к строке (value может иметь любой численный тип данных). Возвращает true при успешном выполнении, false при ошибке. Аналог – сложение, myString + value;
myString.endsWith(myString2);
Проверяет, заканчивается ли myString символами из myString2. В случае совпадения возвращает true
myString.startsWith(myString2);
Проверяет, начинается ли myString символами из myString2. В случае совпадения возвращает true
myString.equals(myString2);
Возвращает true, если myString совпадает с myString2. Регистр букв важен
myString.equalsIgnoreCase (myString2);
Возвращает true, если myString совпадает с myString2. Регистр букв неважен
myString.indexOf(val);
myString.indexOf(val, from);
Ищет и возвращает номер (позицию) значения val в строке, ищет слева направо, возвращает номер первого символа в совпадении. val может быть char или String, то есть ищем в строке другую строку или символ. Можно искать, начиная с позиции from. В случае, когда не может найти val в строке, возвращает -1.
myString.lastIndexOf(val);
myString.lastIndexOf(val, from);
Ищет и возвращает номер (позицию) значения val в строке, ищет справа налево, возвращает номер последнего символа в совпадении. val может быть char или String, то есть ищем в строке другую строку или символ. Можно искать, начиная с позиции from. В случае, когда не может найти val в строке, возвращает -1.
myString.length();
Возвращает длину строки в количестве символов
myString.remove(index);
myString.remove(index, count);
Удаляет из строки символы, начиная с index и до конца, либо до указанного count
myString.replace(substring1, substring2);
В строке myString заменяет последовательность символов substring1 на substring2.
myString.reserve(size);
Зарезервировать в памяти количество байт size для работы со строкой
myString.c_str();
Преобразовывает строку в “СИ” формат (null-terminated string) и возвращает указатель на полученную строку
myString.trim();
Удаляет пробелы из начала и конца строки. Действует со строкой, к которой применяется
myString.substring(from);
myString.substring(from, to);
Возвращает кусок строки, содержащейся в myString начиная с позиции from и до конца, либо до позиции to
myString.toCharArray(buf, len);
Раскидывает строку в массив – буфер buf (типа char []) с начала и до длины len
myString.getBytes(buf, len);
Копирует указанное количество символов len (вплоть до unsigned int) в буфер buf (byte [])
myString.toFloat();
Возвращает содержимое строки в тип данных float
myString.toDouble();
Возвращает содержимое строки в тип данных double
myString.toInt();
Возвращает содержимое строки в тип данных int
myString.toLowerCase();
Переводит все символы в нижний регистр. Было ААААА – станет ааааа
myString.toUpperCase();
Переводит все символы в верхний регистр. Было ааааа – станет ААААА
Длина строки
Небольшой комментарий по поводу длины строки: мы можем узнать длину строки двумя способами, при помощи оператора sizeof() и метода length(). Давайте разберём отличия между ними:
Оператор sizeof вернёт размер строки в байтах. Строка содержит “нулевой символ” на конце, этот символ тоже весит один байт, соответственно оператор вернёт число 6. Метод length возвращает длину строки в количестве символов, не считая завершающий нулевой, поэтому результат будет 5.
F() macro
Строки являются очень тяжёлым с точки зрения использования памяти инструментом, ведь текст в строке хранится в оперативной памяти микроконтроллера, а её не так уж и много. Есть готовый инструмент, позволяющий удобно хранить текстовые данные во Flash памяти микроконтроллера. Этот способ хорош для вывода фиксированных текстовых данных, например, в монитор порта:
Строка “Hello, World!” будет записана во Flash память и не займёт 14 байт (13 + нулевой) в оперативной.
Массивы символов
Массивы символов, они же char array, являются ещё одним способом работы с текстовыми данными. Этот вариант имеет гораздо меньше возможностей по работе с текстом, но зато занимает меньше места в памяти (не используется элемент String) и работает значительно быстрее. К массиву символов применяются те же правила, какие работают для обычных массивов. Рассмотрим пример, в котором объявим массив символов, поработаем с ним, и выведем в порт:
В отличие от строк, массивы символов нельзя:
Длина строки char array
Для определения длины текста можно использовать оператор strlen, который возвращает количество символов в массиве. Сравним его работу с оператором sizeof:
Здесь оператор sizeof вернул количество байт, занимаемое массивом. Массив я специально объявил с размером бОльшим, чем содержащийся в нём текст. А вот оператор strlen посчитал и вернул количество символов, которые идут с начала массива и до нулевого символа в конце текста.
Массив строк
Очень мощной фишкой массивов символов является возможность создать один массив с несколькими строками, и обращаться к ним по номеру. Выглядит это следующим образом:
Данный способ работы со строками хорош тем, что строки хранятся под номерами, и это крайне удобно при работе с дисплеями и в частности создании текстового меню: практически все библиотеки дисплеев умеют выводить массив символов одной командой.
Экономия памяти
“Строки” в массиве строк тоже хранятся в оперативной памяти, что не очень здорово. Ещё больше не здорово то, что применить рассмотренный F() macro к ним нельзя, потому что фактически это не строки. То есть вот такой код приведёт к ошибке:
Как же быть? Массив строк можно сохранить в PROGMEM, программной памяти микроконтроллера, то есть во Flash. Вот такую конструкцию можно использовать как шаблон:
Да, сложно и громоздко, но при большом объёме текстовых данных это может спасти проект!
- Уроки
- Программирование
- Строки и массивы символов
Строки
Строка (String), как понятно из названия, это совокупность символов. По сути строка это одномерный массив типа данных char, про массивы мы уже недавно говорили и вы должны понять, о чём идёт речь. Как и в случае с массивом символов, к каждому элементу строки можно обратиться при помощи квадратных скобок. Основным отличием строки от массива символов является тот факт, что строка – динамический массив, у которого не нужно указывать размер. Также строка является не просто типом данных, а объектом, объектом очень мощного класса String.
Давайте рассмотрим большой пример, из которого будет понятно, как объявить строку и как с ней работать, а также учтены некоторые тонкости:
Как вы могли заметить, строки можно объявлять большим количеством способов, а также буквально складывать строки, как числа, оператором +. Я уже говорил, что строки являются объектами класса String, и у этого класса есть огромное количество удобных методов по работе со строками, далее мы их все рассмотрим с некоторыми примерами. Но для начала запомните вот что: строки – очень тяжёлый инструмент, очень медленный и занимающий кучу памяти: уже просто само наличие строк (от одной и более) в прошивке занимает +5% Flash памяти, т.к. подключается сам “инструмент” – класс String. Для небольших проектов это не страшно, памяти всегда будет навалом.
Инструменты для String
Итак, методы для работы со строками. Как и все методы, они применяются к своим объектам (к строкам) через точку. В рассмотренных ниже примерах строка называется myString.
myString.charAt(index);
Возвращает элемент строки myString под номером index. Аналог – myString[index];
myString.setCharAt(index, val);
Записывает в строку myString символ val на позицию index. Аналог – myString[index] = val;
myString.concat(value);
Присоединяет value к строке (value может иметь любой численный тип данных). Возвращает true при успешном выполнении, false при ошибке. Аналог – сложение, myString + value;
myString.endsWith(myString2);
Проверяет, заканчивается ли myString символами из myString2. В случае совпадения возвращает true
myString.startsWith(myString2);
Проверяет, начинается ли myString символами из myString2. В случае совпадения возвращает true
myString.equals(myString2);
Возвращает true, если myString совпадает с myString2. Регистр букв важен
myString.equalsIgnoreCase (myString2);
Возвращает true, если myString совпадает с myString2. Регистр букв неважен
myString.indexOf(val);
myString.indexOf(val, from);
Ищет и возвращает номер (позицию) значения val в строке, ищет слева направо, возвращает номер первого символа в совпадении. val может быть char или String, то есть ищем в строке другую строку или символ. Можно искать, начиная с позиции from. В случае, когда не может найти val в строке, возвращает -1.
myString.lastIndexOf(val);
myString.lastIndexOf(val, from);
Ищет и возвращает номер (позицию) значения val в строке, ищет справа налево, возвращает номер последнего символа в совпадении. val может быть char или String, то есть ищем в строке другую строку или символ. Можно искать, начиная с позиции from. В случае, когда не может найти val в строке, возвращает -1.
myString.length();
Возвращает длину строки в количестве символов
myString.remove(index);
myString.remove(index, count);
Удаляет из строки символы, начиная с index и до конца, либо до указанного count
myString.replace(substring1, substring2);
В строке myString заменяет последовательность символов substring1 на substring2.
myString.reserve(size);
Зарезервировать в памяти количество байт size для работы со строкой
myString.c_str();
Преобразовывает строку в “СИ” формат (null-terminated string) и возвращает указатель на полученную строку
myString.trim();
Удаляет пробелы из начала и конца строки. Действует со строкой, к которой применяется
myString.substring(from);
myString.substring(from, to);
Возвращает кусок строки, содержащейся в myString начиная с позиции from и до конца, либо до позиции to
myString.toCharArray(buf, len);
Раскидывает строку в массив – буфер buf (типа char []) с начала и до длины len
myString.getBytes(buf, len);
Копирует указанное количество символов len (вплоть до unsigned int) в буфер buf (byte [])
myString.toFloat();
Возвращает содержимое строки в тип данных float
myString.toDouble();
Возвращает содержимое строки в тип данных double
myString.toInt();
Возвращает содержимое строки в тип данных int
myString.toLowerCase();
Переводит все символы в нижний регистр. Было ААААА – станет ааааа
myString.toUpperCase();
Переводит все символы в верхний регистр. Было ааааа – станет ААААА
Длина строки
Небольшой комментарий по поводу длины строки: мы можем узнать длину строки двумя способами, при помощи оператора sizeof() и метода length(). Давайте разберём отличия между ними:
Оператор sizeof вернёт размер строки в байтах. Строка содержит “нулевой символ” на конце, этот символ тоже весит один байт, соответственно оператор вернёт число 6. Метод length возвращает длину строки в количестве символов, не считая завершающий нулевой, поэтому результат будет 5.
F() macro
Строки являются очень тяжёлым с точки зрения использования памяти инструментом, ведь текст в строке хранится в оперативной памяти микроконтроллера, а её не так уж и много. Есть готовый инструмент, позволяющий удобно хранить текстовые данные во Flash памяти микроконтроллера. Этот способ хорош для вывода фиксированных текстовых данных, например, в монитор порта:
Строка “Hello, World!” будет записана во Flash память и не займёт 14 байт (13 + нулевой) в оперативной.
Массивы символов
Массивы символов, они же char array, являются ещё одним способом работы с текстовыми данными. Этот вариант имеет гораздо меньше возможностей по работе с текстом, но зато занимает меньше места в памяти (не используется элемент String) и работает значительно быстрее. К массиву символов применяются те же правила, какие работают для обычных массивов. Рассмотрим пример, в котором объявим массив символов, поработаем с ним, и выведем в порт:
В отличие от строк, массивы символов нельзя:
Длина строки char array
Для определения длины текста можно использовать оператор strlen, который возвращает количество символов в массиве. Сравним его работу с оператором sizeof:
Здесь оператор sizeof вернул количество байт, занимаемое массивом. Массив я специально объявил с размером бОльшим, чем содержащийся в нём текст. А вот оператор strlen посчитал и вернул количество символов, которые идут с начала массива и до нулевого символа в конце текста.
Массив строк
Очень мощной фишкой массивов символов является возможность создать один массив с несколькими строками, и обращаться к ним по номеру. Выглядит это следующим образом:
Данный способ работы со строками хорош тем, что строки хранятся под номерами, и это крайне удобно при работе с дисплеями и в частности создании текстового меню: практически все библиотеки дисплеев умеют выводить массив символов одной командой.
Экономия памяти
“Строки” в массиве строк тоже хранятся в оперативной памяти, что не очень здорово. Ещё больше не здорово то, что применить рассмотренный F() macro к ним нельзя, потому что фактически это не строки. То есть вот такой код приведёт к ошибке:
Как же быть? Массив строк можно сохранить в PROGMEM, программной памяти микроконтроллера, то есть во Flash. Вот такую конструкцию можно использовать как шаблон:
Да, сложно и громоздко, но при большом объёме текстовых данных это может спасти проект!
Arduino String – основная библиотека для работы со строками в ардуино. С ее помощью существенно упрощается использование массивов символов и строк в скетче. Объект типа String содержит множество полезных функций для создания и объединения строк, преобразований string to int (парсинг чисел) и int to string (форматирование чисел). Строки используются практически в любых проектах, поэтому и вероятность встретить String в скетче очень высока. В этой статье мы постараемся рассмотреть основные методы этого класса и наиболее часто возникающие ситуации.
Для чего нужен String в ардуино
Стандартным способом работы со строками в языке C является использование массива символов. Это все означало необходимость работы с указателями и понимания адресной арифметики. В ардуино и C++ у программистов появилось гораздо больше возможностей. Все “низкоуровневые” операции по работе со строкой выделены в отдельный класс, а для основных операций даже переопределены операторы. Например, для объединения срок мы просто используем хорошо знакомый знак “+”, а не зубодробильные функции типа malloc и strcpy. С помощью String мы работаем со строкой как с целым объектом, а не рассматриваем его как массив символов. Это позволяет сосредоточиться на логике скетча, а не деталях реализации хранения символов в памяти.
Естественно, у любого “упрощения” всегда есть свои подводные камни. String всегда использует больше оперативной памяти и в некоторых случаях функции класса могут медленнее обрабатываться. Поэтому в реальных больших проектах придется тщательно взвешивать все плюсы и минусы и не забывать, что никто не мешает нам работать со строками в стиле С. Все обычные функции обработки массивов char остаются в нашем арсенале и в arduino.
Создание строк в ардуино с помощью String
В ардуино у нас есть несколько способов создать строку, приведем основные:
- char myCharStr [ ] = “Start”; – массив типа char с завершающим пустым символом;
- String myStr = “Start”; – объявляем переменную, создаем экземпляр класса String и записываем в него константу-строку.
- String myStr = String(“Start”); – аналогичен предыдущему: создаем строку из константы
- String myStr(myCharStr); – создаем объект класса String с помощью конструктра, принимающего на вход массив типа char и создающего из char String.
- String myStr = String(50); – создаем строку из целого числа (преобразование int to string).
- String myStr = String(30, H); – создаем строку – представление числа в 16-чной системе (HEX to String)
- String myStr = String(16, B); – создаем строку – представление числа в двоичной системе (Byte to String).
Каждый раз, когда мы объявляем в коде строку с использованием двойных кавычек, мы создаем неявный объект класса String, являющийся константой. При этом обязательно использование именно двойных кавычек: “String” – это строка. Одинарные кавычки нужны для обозначения отдельных символов. ‘S’ – это символ.
Функции и методы класса String
Для работы со строками в String предусмотрено множество полезных функций. Приведем краткое описание каждой из них:
- String() – конструктор, создает элемент класса данных string. Возвращаемого значения нет. Есть множество вариантов, позволяющих создавать String из строк, символов, числе разных форматов.
- charAt() возвращает указанный в строке элемент. Возвращаемое значение – n-ный символ строки.
- compareTo() – функция нужна для проверки двух строк на равенство и позволяет выявить, какая из них идет раньше по алфавиту. Возвращаемые значения: отрицательное число, если строка 1 идет раньше строки 2 по алфавиту; 0 – при эквивалентности двух строк; положительное число, если вторая строка идет раньше первой в алфавитном порядке.
- concat() – функция, которая объединяет две строки в одну. Итог сложения строк объединяется в новый объект String.
- startsWith() – функция показывает, начинается ли строка с символа, указанного во второй строке. Возвращаемое значение: true, если строка начинается с символа из второй строки, в ином случае false.
- endsWith() – работает так же, как и startsWith(), но проверяет уже окончание строки. Также возвращает значения true и false.
- equals() – сравнивает две строки с учетом регистра, т.е. строки «start» и «START» не будут считаться эквивалентными. Возвращаемые значения: true при эквивалентности, false в ином случае.
- equalsIgnoreCase() – похожа на equals, только эта функция не чувствительна к регистру символов.
- getBytes() – позволяет скопировать символы указанной строки в буфер.
- indexOf() – выполняет поиск символа в строке с начала. Возвращает значение индекса подстроки val или -1, если подстрока не обнаружена.
- lastIndexOf() –выполняет поиск символа в строке с конца.
- length() – указывает длину строки в символах без учета завершающего нулевого символа.
- replace() – заменяет в строке вхождения определенного символа на другой.
- setCharAt() – изменяет нужный символ в строке.
- substring() – возвращает подстроку. Может принимать два значения – начальный и конечный индексы. Первый является включительным, т.е. соответствующий ему элемент будет включаться в строку, второй – не является им.
- toCharArray() – копирует элементы строки в буфер.
- toLowerCase() – возвращает строку, которая записана в нижнем регистре.
- toUpperCase() – возвращает записанную в верхнем регистре строку.
- toInt() – позволяет преобразовать строку в число (целое). При наличии в строке не целочисленных значений функция прерывает преобразование.
- trim() – отбрасывает ненужные пробелы в начале и в конце строки.
Объединение строк Arduino
Объединить две строки в одну можно различными способами. Эта операция также называется конкатенацией. В ее результате получается новый объект String, состоящий из двух соединенных строк. Добавить к строке можно различные символы:
- String3 = string1 + 111; // позволяет прибавить к строке числовую константу. Число должно быть целым.
- String3 = string1 + 111111111; // добавляет к строке длинное целое число
- String3 = string1 + ‘А’; // добавляет символ к строке
- String3 = string1 + “aaa”;// добавляет строковую постоянную.
- String3 = string1 + string2; // объединяет две строки вместе.
Важно осторожно объединять две строки из разных типов данных, так как это может привести к ошибке или неправильному результату.
Arduino string to int и string to float
Для конвертации целочисленных значений string to int используется функция toInt().
String MyStr = “111”;
int x = MyStr.toInt();
Если нужно конвертировать объект с плавающей запятой, применяется функция atof().
String MyStr = “11.111”;
MyStr.toCharArray(myStr1, MyStr.length()); // копируется String в массив myStr1
float x = atof(myStr1); // преобразование в float
Преобразование int to string
Для создания строки из числа не требуется делать особых телодвижений. Мы можем просто объединить строку и число:
String str = “Строка номер “+ i;
Можем создать объект, используя конструктор
String str = String(50);
Можем объединить оба способа:
String str = “Строка номер “+ String(50);
Преобразование String в массив char
Тип данных Char позволяет объявлять текстовые строки несколькими способами:
- char myStr1[10]; – в данном случае объявлен массив определенного размера.
- char myStr2 [6] = <‘a’, b, ‘c’, ‘d’, ‘e’>; – объявлен сам массив. Конечный символ не записанявно, его прибавит сам компилятор.
- char myStr3[6] = <‘a’, b, ‘c’, ‘d’, ‘e’’/0’>; – объявлен массив, при этом в конце прописан признак окончания строки.
- char myStr4 [ ] = “abcde”; – инициализация массива строковой постоянной. Размер и завершающий символ добавляются автоматически компилятором.
- char myStr5 [6 ] = “abcde”; – инициализация массива с точным указанием его размера.
- char myStr 6[30 ] = “abcde”; – аналогично, но размер указан больше для возможности использования строк большей длины.
Еще раз напомним, что в типе данных char строковые константы нужно записывать в двойные кавычки «Abcde», а одиночные символы – в одинарные ‘a’.
Конвертировать строку в массив сhar array можно при помощи следующего кода:
String stringVar = “111”;
Можно сделать обратное преобразование – char to string.
char[] chArray = “start”;
Пример преобразования String to const char*. Указание звездочкой char*означает, что это массив указателей.
String stringVar=string (`start);
Char charVar[ sizeof [stringVar)];
Заключение о String и ардуино
В этой статье мы рассмотрели основные вопросы использования String для работы со строками arduino. Как показывают примеры, ничего страшного и сложного в этом классе нет. Более того, зачастую мы можем даже не догадываться, что работаем с классом String: мы просто создаем переменную нужного типа, присваиваем ей строку в двойных кавычках. Создав строку, мы используем все возможности библиотеки String: можем без проблем модифицировать строку, объединять строки, преобразовывать string в int и обратно, а также делать множество других операций с помощью методов класса.
В ситуациях, когда скетч большой и перед нами встает дефицит памяти, использовать String нужно осторожно, по возможности заменяя на char*. Впрочем, в большинстве первых проектов начинающего ардуинщика таких ситуаций не много, поэтому рекомендуем использовать String без опаски – это предотвратит появление ошибок адресной арифметики, возникающих при работе с массивами char.