Освой Arduino играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

String

08.StringConstructors
08.StringCaseChanges
StringCharacters
08.StringIndexOf
08.StringStartsWithEndsWith
Строковые функции языка C

Строка может быть в двойных кавычках (массив символов), одиночным символом в одинарных кавычках, экземпляром объекта String.

Нужно помнить, что в языке C строка должна завершаться нулевым символом ('\0'), поэтому при создании строки нужно указывать на один символ больше. Иногда компилятор может догадаться самостоятельно добавлять нулевой символ, но в некоторых случаях он не поможет.


//char name[] = {'B', 'a', 'r', 's', 'i', 'k', '\0'};
//char name[7] = {'B', 'a', 'r', 's', 'i', 'k', '\0'};
//char name[] = {'B', 'a', 'r', 's', 'i', 'k'};
//char name[6] = {'B', 'a', 'r', 's', 'i', 'k'};

void setup() {
  // Попробуйте все варианты
  char name[] = {'B', 'a', 'r', 's', 'i', 'k', '\0'};
  Serial.begin(9600);
  Serial.print(name);
}

void loop() {

}

Иногда массив строк записывают как указатель на символ (первый символ в массиве):


char *message = "Hello Kitty";

Строка как отдельный тип относится уже к языку C++. Вам не нужно указывать массив отдельных символов, достаточно просто окружить строку двойными кавычками. У класса String есть несколько удобных функций для работы со строками.

Только помните, что класс String требует больше ресурсов, чем при работе с массивами символов. Проведём эксперимент. Напишем первый скетч с использованием String.


void setup() {
  Serial.begin(9600);
  String firstName = "Alexander";
  String lastName = "Klimov";
  String fullName = firstName + " " + lastName;
  Serial.println(fullName);
}

void loop() {}

При компиляции вывелось следующее: Sketch uses 3212 bytes (9%) of program storage space. Maximum is 32256 bytes. Global variables use 216 bytes (10%) of dynamic memory, leaving 1832 bytes for local variables. Maximum is 2048 bytes.

Перепишем пример.


void setup() {
  Serial.begin(9600);
  char myName[16] = "Alexander ";
  char lastName[] = "Klimov";
  strcat(myName, lastName);
  Serial.println(myName);
}
void loop() {}

На этот раз выводится Sketch uses 1618 bytes (5%) of program storage space. Maximum is 32256 bytes. Global variables use 210 bytes (10%) of dynamic memory, leaving 1838 bytes for local variables. Maximum is 2048 bytes.

Второй скетч использует 5% памяти вместо 9%, т.е. почти в два раза меньше. Для сложных проектов подобное использование строк может стать решающим фактором.

08.StringConstructors

Пример File | Examples | 08.Strings | StringConstructors. - манипуляции со строками: объединить две строки, конвертировать символ в строку, конвертировать число в строку в разных системах счисления.


void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // send an intro:
  Serial.println("\n\nString Constructors:");
  Serial.println();
}

void loop() {
  // обычная строка
  String stringOne = "Hello String";
  Serial.println(stringOne);      // prints "Hello String"

  // конвертируем символ в строку:
  stringOne =  String('a');
  Serial.println(stringOne);       // prints "a"

  // конвертируем строку в объект String:
  String stringTwo =  String("This is a string");
  Serial.println(stringTwo);      // prints "This is a string"

  // соединяем две строки:
  stringOne =  String(stringTwo + " with more");
  // prints "This is a string with more":
  Serial.println(stringOne);

  // число в строку:
  stringOne =  String(13);
  Serial.println(stringOne);      // prints "13"

  // число строку, выбирая формат, например, десятичный:
  stringOne =  String(analogRead(A0), DEC);
  // prints "453" or whatever the value of analogRead(A0) is
  Serial.println(stringOne);

  // шестнадцатеричный:
  stringOne =  String(45, HEX);
  // prints "2d", which is the hexadecimal version of decimal 45:
  Serial.println(stringOne);

  // бинарный
  stringOne =  String(255, BIN);
  // prints "11111111" which is the binary value of 255
  Serial.println(stringOne);

  // большое число типа long:
  stringOne =  String(millis(), DEC);
  // prints "123456" or whatever the value of millis() is:
  Serial.println(stringOne);

  // число с плавающей точкой с тремя разрядами после запятой:
  stringOne = String(5.698, 3);
  Serial.println(stringOne);

  // с округлением до двух знаков после запятой:
  stringOne = String(5.698, 2);
  Serial.println(stringOne);

  // do nothing while true:
  while (true);

}

08.StringCaseChanges

Переводим строку в верхний или нижний регистр с помощью функций toUpperCase() и toLowerCase() в примере File | Examples | 08.Strings | StringCaseChanges.


void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // send an intro:
  Serial.println("\n\nString case changes:");
  Serial.println();
}

void loop() {
  // toUpperCase() преобразует все символы в верхний регистр:
  String stringOne = "<html><head><body>";
  Serial.println(stringOne);
  stringOne.toUpperCase();
  Serial.println(stringOne);

  // toLowerCase() преобразует все символы в нижний регистр:
  String stringTwo = "</BODY></HTML>";
  Serial.println(stringTwo);
  stringTwo.toLowerCase();
  Serial.println(stringTwo);


  // do nothing while true:
  while (true);
}

StringCharacters

Функция charAt() позволяет узнать символ в указанной позиции строки. Функция setCharAt() позволяет заменить символ в указанной позиции.

Возьмём пример File | Examples | 08.Strings | StringCharacters и немного переделаем его немного.


void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
}

void loop() {
  String reportString = "Земля держится на 3 китах";
  Serial.println(reportString);

  // получим символ в позиции 33:
  char mostSignificantDigit = reportString.charAt(33);

  String message = "Символ в указанной позиции: ";
  Serial.println(message + mostSignificantDigit);

  Serial.println();

  // Меняем символ и на о
  reportString.setCharAt(38, 'о');
  Serial.println(reportString);

  // do nothing while true:
  while (true);
}

Этот пример показывает, что нужно быть осторожным при работе с символами, которые не входят в состав ANSI, например, русскими. Если вы посчитаете, то увидите, что символ '3' находится на 19 позиции. Старайтесь работать с английским текстом, чтобы избежать путаницы.

charAt

08.StringIndexOf

Пример показывает применение функций indexOf() и lastIndexOf(). Функции находят первое вхождение символа в строке с начала или конца строки. Также можно указать смещение, с которого следует начинать поиск вхождения.


void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("\n\nString indexOf() and lastIndexOf()  functions:");
  Serial.println();
}

void loop() {
  // indexOf() возвращает позицию (индекс) указанного символа
  String stringOne = "<HTML><HEAD><BODY>";
  int firstClosingBracket = stringOne.indexOf('>'); // ищем первую закрывающую угловую скобку
  Serial.println("The index of > in the string " + stringOne + " is " + firstClosingBracket);

  stringOne = "<HTML><HEAD><BODY>";
  int secondOpeningBracket = firstClosingBracket + 1;
  int secondClosingBracket = stringOne.indexOf('>', secondOpeningBracket); // вторая закрывающая скобка
  Serial.println("The index of  the second > in the string " + stringOne + " is " + secondClosingBracket);

  // можно также использовать indexOf() для поиска строк:
  stringOne = "<HTML><HEAD><BODY>";
  int bodyTag = stringOne.indexOf("<BODY>");
  Serial.println("The index of the body tag in the string " + stringOne + " is " + bodyTag);

  stringOne = "<UL><LI>item<LI>item<LI>item</UL>";
  int firstListItem = stringOne.indexOf("<LI>");
  int secondListItem = stringOne.indexOf("<LI>", firstListItem + 1);
  Serial.println("The index of the second list tag in the string " + stringOne + " is " + secondListItem);

  // lastIndexOf() находит последнее вхождение символа или строки
  int lastOpeningBracket = stringOne.lastIndexOf('<');
  Serial.println("The index of the last < in the string " + stringOne + " is " + lastOpeningBracket);

  int lastListItem  = stringOne.lastIndexOf("<LI>");
  Serial.println("The index of the last list tag in the string " + stringOne + " is " + lastListItem);


  // lastIndexOf() может искать строку:
  stringOne = "<p>Lorem ipsum dolor sit amet</p><p>Ipsem</p><p>Quod</p>";
  int lastParagraph = stringOne.lastIndexOf("<p");
  int secondLastGraf = stringOne.lastIndexOf("<p", lastParagraph - 1);
  Serial.println("The index of the second to last paragraph tag " + stringOne + " is " + secondLastGraf);

  // do nothing while true:
  while (true);
}

08.StringStartsWithEndsWith

Функции startsWith() и endsWith() позволяют узнать, начинается или заканчивается строка на заданный символ (подстроку).


void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("\n\nString startsWith() and endsWith():");
  Serial.println();
}

void loop() {
  // startsWith() проверят, начинается ли строка со слов HTTP/1.1:
  String stringOne = "HTTP/1.1 200 OK";
  Serial.println(stringOne);
  if (stringOne.startsWith("HTTP/1.1")) {
    Serial.println("Server's using http version 1.1");
  }

  // также можно использовать startsWith() с небольшим смещением:
  stringOne = "HTTP/1.1 200 OK";
  if (stringOne.startsWith("200 OK", 9)) {
    Serial.println("Got an OK from the server");
  }

  // endsWith() проверяет, заканчивается ли строка на заданный символ
  String sensorReading = "sensor = ";
  sensorReading += analogRead(A0);
  Serial.print(sensorReading);
  if (sensorReading.endsWith("0")) {
    Serial.println(". This reading is divisible by ten");
  } else {
    Serial.println(". This reading is not divisible by ten");
  }

  // do nothing while true:
  while (true);
}

Строковые функции языка C

Кроме функций для строк из библиотеки Arduino, есть родные строковые функции самого языка C, например, sprintf(), которая выполняет форматирование массивов символов.

Допустим, мы хотим вывести информацию на двух строках ЖК-дисплея:


char line1[17];
int tempC = 30;
sprint(line1, "Temp: %d C", tempC);

char line2[17];
int h = 12;
int m = 30;
int s = 5;
sprintf(line2, "Time: %2d:%02d:%02d", h, m, s);

Массив символов line1 — это строковый буфер, содержащий форматированный текст, который имеет ёмкость 17 символов, включая завершающий нулевой символ.

В первом параметре функции передаётся массив символов, в который должен быть записан результат. Следующий аргумент — строка формата, содержащая смесь простого текста, такого как "Temp:", и команд форматирования, например %d. В данном случае %d означает «десятичное целое со знаком». Остальные параметры будут подставлены в строку формата в порядке их следования на место команд форматирования.

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


Time: 12:30:05

Команда sprintf() не только подставила числа в нужные места, но и добавила ведущий ноль перед цифрой 5. В примере между символами : находятся команды форматирования трёх компонентов времени. Часам соответствует команда %2d, которая выводит двузначное десятичное число. Команды форматирования для минут и секунд немного отличаются (%02d). Эти команды также выводят двузначные десятичные числа, но добавляют ведущий ноль, если это необходимо. Однако имейте в виду, что этот приём предназначен для значений типа int.

Определить длину строки можно через strlen().


strlen("cat"); // вернёт 3
Реклама