Урок 9: Строки String

Создание строк

Строка

Это последовательность символов заключенная в кавычки двойные или одинарные

Важно выбрать один стиль и придерживаться его во всем коде для повышения читаемости.


String str1 = "Обычная строка в вдойных кавычках";
String str2 = 'Обычная строка в одинарных кавычках';

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

Советую двойные кавычки.

Многострочные строки

Если нужно создать строку, которая занимает несколько строк в коде, используйте тройные кавычки:


String multStr = '''
  Это многострочная строка,
  которая продолжается на несколько строк.
  Довольно удобно!
''';

Пустые строки

Все строки, включая пустые, считаются строками (тип данных String)

Все примеры ниже являются строками!


String text1 = "Привет";
String text2 = "";
String text3 = " ";
String text4 = "12345";
String text5 = "😎🧐";  // Строка может содержать эмодзи!

Повторение строк

Для повторения строки несколько раз используется оператор умножения:


print("Привет! " * 3);  // Привет! Привет! Привет!

Конкатенация строк

Конкатенация

Это объединение нескольких строк в одну.

В Dart строки можно объединять с помощью оператора +


void main() {
  String text1 = "Привет,";
  String text2 = "Юля";
  String result = text1 + text2;

  print(result); // "Привет, Юля"
}

Интерполяция строк

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

Можно это сделать намного лучше и элегантней - шаблонные строки

Шаблонные строки - `интерполяция`

Интерполяция строк позволяет вставлять значения переменных и выражений прямо в строку.

Для этого используйте знак $ для одной переменной или ${} для сложного выражения.


void main() {
  int countMessage = 10;
  print("У вас " + countMessage.toString() + "сообщений" );

  // Использование интерполяции
  print("У вас $countMessage сообщений");
  // У вас 10 сообщений

  // Если выполняется более сложное выражение
  // Нужно обернуть его в { }
  print("У вас ${countMessage + 1} сообщений");
  // У вас 11 сообщений
}

Экранирование символов

Если в строках нужно использовать специальные символы, такие как кавычки, символы новой строки, табуляции и т.д., используйте escape-последовательности.


void main() {
  print("'H' первая буква строки \"Hello world!\"");
  print("Первая строка \nВторая строка");
}

// 'H' - первая буква строки "Hello world!"
// Первая строка
// Вторая строка

Вот некоторые распространенные `escape-последовательности`

\n → новая строка

\t → табуляция

\' → одинарная кавычка

\" → двойная кавычка

Работа с отдельными символами строки

Коллекция символов

Строки в Dart — это последовательности символов, и вы можете обращаться к отдельным символам строки через индексы, как в массиве.

image.png

String text = "Привет";

print(text[0]); // П
print(text[1]); // р
print(text[2]); // и
print(text[3]); // в
print(text[4]); // е
print(text[5]); // т

Ограничения - Строки неизменяемые

Все строки `неизменяемые` (`immutable`)

Строки в Dart — неизменяемые. Вы не можете изменить отдельный символ строки!


String text = "Привет";
text[0] = "п"; // Ошибка!

Методы работы со строками

Проверка длины строки и пустоты

Вы можете проверить длину строки с помощью свойства length и проверить, пуста ли строка, с помощью isEmpty


String s = "Hello, Dart!";

print(s.length);  // 13
print(s.isEmpty);  // false

// Cтрока состоящая из пробелов не считается пустой!
print(''.isEmpty); // true
print(' '.isEmpty); // false

Преобразование регистра

Вы можете преобразовать строку в верхний или нижний регистр


String s = "Hello, Dart!";
print(s.toUpperCase());  // HELLO, DART!
print(s.toLowerCase());  // hello, dart!

Удаление пробелов

Для удаления пробелов по краям строки - методы trim(), trimLeft(), trimRight()


String s = "  Hello, Dart!  ";
print(s.trim());     // "Hello, Dart!" 
print(s.trimLeft());  // "Hello, Dart!  "
print(s.trimRight()); // "  Hello, Dart!"

Извлечение подстроки

Используйте метод substring() для извлечения части строки


String s = "Hello, Dart!";
print(s.substring(0, 5));  // Hello

Поиск в строке

Используйте методы для поиска внутри строки contains() startsWith() endsWith()


var name = 'IT-Квантум';

// Содержит ли строка другую строку
print(name.contains('Квантум')); // true

// Начинается ли строка с другой строки
print(name.startsWith('IT')); // true

// Заканчивается ли строка другой строкой
print(name.endsWith('ум')); // true

// Найти положение(индекс) строки в другой строке
print(name.indexOf('Ква')); // 3

Разделение строки

Метод split() разделяет строку на подстроки с помощью разделителя в скобках


String s = "Hello Dart";

List parts = s.split(" ");

print(parts.lenght); // 2
print(parts);  // ["Hello", "Dart"]

Замена подстроки

Метод replaceAll() позволяет заменить все вхождения подстроки:


String s = "Hello Dart";
String result = s.replaceAll("Dart", "Flutter");
print(result);  // Hello Flutter

Преобразование строки в число

Используйте методы int.parse() и double.parse() для преобразования строк в числа:


int digit = int.parse("42");
double ddigit = double.parse("3.14");

print(digit);  // 42
print(ddigit);  // 3.14

Для безопасного преобразования используйте tryParse():


int? digit = int.tryParse('abc');
print(digit);  // null

Преобразование числа в строку

Методы toString() и toStringAsFixed() используются для преобразования чисел обратно в строки


int num = 42;
double pi = 3.14159;
print(num.toString());  // "42"
print(pi.toStringAsFixed(2));  // "3.14"

Дополнительно

Использование StringBuffer

Конкатенация строк через `StringBuffer`

Создать объект StringBuffer, методом write добавить отдельные строки.

Результат - приведение к строке методом toString, который объединит всё в одну строку. Это удобный и эффективный способ, если входных строк очень много.

StringBuffer - Класс для эффективного объединения строк.


List strings = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

StringBuffer buffer = StringBuffer();

buffer
..write('!')
..writeAll(strings)
..write('.');

var fullString = buffer.toString();
print('StringBuffer: $fullString');

Регулярные выражения


// * Задать правило для регулярного выражения через класс RegExp()
// * Найти и выбрать все цифровые значения в строке

var numbers = RegExp(r'\d+');
var allCharacters = 'Dart & Flutter';
var someDigits = 'Dart 2.15 & Flutter 2.6.0';

// ? Содержит ли строка цифры
print(allCharacters.contains(numbers)); // false
print(someDigits.contains(numbers)); // true

// ? Заменить каждое совпадение в строке
var exedOut = someDigits.replaceAll(numbers, 'XX');
print(exedOut); // Dart XX.XX.XX & Flutter XX.XX.XX

// * Также можно работать непосредсвенно с классом RegExp()
// hasMatch - когда регулярка имеет совпадение в строке
print(numbers.hasMatch(someDigits)); // true

// Показать все совпадения
for (var match in numbers.allMatches(someDigits)) {
  print(match.group(0));
}

Символы и Руны


// ! Строка представлена последовательностью единиц кода Unicode UTF-16, доступной через элементы codeUnitAt или codeUnits:
string = 'Dart';
print(string.codeUnitAt(0)); // 68
print(string.codeUnits); // [68, 97, 114, 116]

// ! Строковое представление единиц кода доступно через оператор индекса:
string[0]; // D

// ! Символы строки (characters of a string) кодируются в UTF-16. Декодирование UTF-16, которое объединяет пары, возвращает код в Unicode.

// Следуя терминологии, аналогичной в языке Go, мы используем имя «руна» rune для целого числа, представляющего кодовую точку Unicode. Используйте свойство runes, чтобы получить руны строки:

(string.runes.toList()); // [68, 97, 114, 116]

// ! Чтобы не мучаться с парой возвращаемых значений для символов, руны объединяют эту пару и возвращают одно целое число. Например, символ Unicode для музыкального G-ключа ('𝄞') со значением руны 0x1D11E состоит из пары UTF-16: 0xD834 и 0xDD1E. Использование codeUnits возвращает пару, а использование рун возвращает их объединенное значение:

// var clef = '\u{1D11E}';

var clef = '𝄞';
var pumpkin = '🎃';
print(clef.codeUnits); // [55348, 56606] Hex: [0xD834, 0xDD1E]
print(clef.runes.toList()); // [119070] Hex: [0x1D11E]
print(pumpkin);
print(pumpkin.codeUnits);

// ! И ещё для более удобной работы и ожидаемого поведения, рекомендуется использовать официальный пакет characters 1.2.0 (на основе этих рун)
// https://pub.dev/packages/characters
// ? Например, есть строка c эмоодзи.
// Если обратиться к последнему символу, то будет ерунда
// Для нормального поведения нужно использовать characters

var iLovePumpkin = 'I Love Pumpkin 🎃';
print(iLovePumpkin);
print('ТЫКОВКА: ${iLovePumpkin.substring(iLovePumpkin.length-1)}');
print('ТЫКОВКА: ${iLovePumpkin.characters.last}');

// Можно это проследить по размеру строки, она отличается 17 вместо 16
print(iLovePumpkin.length);
print(iLovePumpkin.characters.length);

// ! Так же в дарте есть ещё один тип похожий строки это Symbols, он нужен для постоянной идентификации объекта (исп. обычно в API, чтобы при модификации значений, символы никогда не изменятся)

// Но использовать их мы не будем практически никогда, в этом курсе точно.
//* #id
//* #symbols