Как найти емкость строки

Добавлено 2 октября 2021 в 16:01

После того, как вы создали строку, часто бывает полезно узнать ее длину. Здесь в игру вступают операции с длиной и емкостью.

Длина строки

Длина строки – это довольно просто, это количество символов в строке. Для определения длины строки есть две идентичные функции:

size_type string::length() const
size_type string::size() const

Обе эти функции возвращают текущее количество символов в строке, исключая завершающий ноль.

Пример кода:

string sSource("012345678");
cout << sSource.length() << endl;

Вывод:

9

Хотя, чтобы определить, есть ли в строке какие-либо символы или нет, можно использовать length(), но более эффективно использовать функцию empty():

bool string::empty() const

Возвращает true, если в строке нет символов, иначе – false.

Пример кода:

string sString1("Not Empty");
cout << (sString1.empty() ? "true" : "false") << endl;
string sString2; // пустая
cout << (sString2.empty() ? "true" : "false")  << endl;

Вывод:

false
true

Есть еще одна функция, связанная с размером, которую вы, вероятно, никогда не будете использовать, но мы опишем ее здесь для полноты картины:

size_type string::max_size() const

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

Пример кода:

string sString("MyString");
cout << sString.max_size() << endl;

Вывод:

4294967294

Емкость строки

Емкость (вместимость) строки показывает, сколько памяти выделено объектом строки для хранения ее содержимого. Это значение измеряется в строковых символах, исключая символ завершающего нуля. Например, строка с емкостью 8 может содержать 8 символов.

size_type string::capacity() const

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

Пример кода:

string sString("01234567");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

Вывод:

Length: 8
Capacity: 15

Обратите внимание, что емкость больше, чем длина строки! Хотя длина нашей строки равна 8, на самом деле она занимала достаточно памяти для 15 символов! Зачем так сделано?

Здесь важно понимать, что если пользователь хочет поместить в строку больше символов, чем позволяет ее емкость, то для получения большей емкости строка должна быть перераспределена в памяти. Например, если строка имеет длину и емкость 8, то добавление любых символов в строку приведет к переразмещению объекта в памяти. Сделав емкость больше размера фактической строки, пользователь получил некоторое буферное пространство для расширения строки до необходимости перераспределения.

Как оказалось, перераспределение – это плохо по нескольким причинам:

Во-первых, перераспределение строки относительно дорого. Сначала необходимо выделить новую память. Затем каждый символ в строке необходимо скопировать в новую память. Если строка большая, это может занять много времени. Наконец, необходимо освободить старую память. Если вы выполняете много перераспределений, этот процесс может значительно замедлить работу вашей программы.

Во-вторых, всякий раз, когда строка перераспределяется, адрес содержимого строки в памяти изменяется на новое значение. Это означает, что все ссылки, указатели и итераторы строки становятся недействительными!

Обратите внимание, что строки не всегда размещаются с емкостью, превышающей длину. Рассмотрим следующую программу:

string sString("0123456789abcde");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

Эта программа выводит:

Length: 15
Capacity: 15

Результаты могут отличаться в зависимости от компилятора.

Давайте добавим к строке один символ и посмотрим, как изменится емкость:

string sString("0123456789abcde");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

// Теперь добавим новый символ
sString += "f";
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

Это дает следующий результат:

Length: 15
Capacity: 15
Length: 16
Capacity: 31

void string::reserve()
void string::reserve(size_type unSize)

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

Если вызывается первый вариант этой функции или второй вариант вызывается с unSize, меньшим, чем текущая емкость, функция попытается уменьшить емкость, чтобы она соответствовала длине. Этот запрос необязателен для выполнения.

Пример кода:

string sString("01234567");
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

sString.reserve(200);
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

sString.reserve();
cout << "Length: " << sString.length() << endl;
cout << "Capacity: " << sString.capacity() << endl;

Вывод:

Length: 8
Capacity: 15
Length: 8
Capacity: 207
Length: 8
Capacity: 207

В этом примере показаны две интересные вещи. Во-первых, хотя мы запросили емкость 200, на самом деле мы получили емкость 207. Гарантируется, что емкость всегда будет не меньше, чем вы запросили, но может быть и больше. Затем мы запросили изменение емкости, чтобы она соответствовала длине строки. Этот запрос был проигнорирован, так как емкость не изменилась.

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

#include <iostream>
#include <string>
#include <cstdlib> // для rand() и srand()
#include <ctime>   // для time()

using namespace std;

int main()
{
    std::srand(std::time(nullptr)); // инициализация генератора случайных чисел

    string sString{};    // длина 0
    sString.reserve(64); // резервируем 64 символа

    // Заполняем строку случайными строчными буквами
    for (int nCount{ 0 }; nCount < 64; ++nCount)
        sString += 'a' + std::rand() % 26;

    cout << sString;
}

Результат этой программы будет меняться каждый раз. Вот результат одного выполнения:

wzpzujwuaokbakgijqdawvzjqlgcipiiuuxhyfkdppxpyycvytvyxwqsbtielxpy

Вместо того чтобы перераспределять sString несколько раз, мы устанавливаем емкость один раз, а затем заполняем строку. Это может очень влиять на производительность при формировании больших строк с помощью конкатенации.

Теги

C++ / CppLearnCppstd::stringstd::wstringSTL / Standard Template Library / Стандартная библиотека шаблоновДля начинающихЕмкостьОбучениеПрограммирование

Определить объём текста

Онлайн калькулятор легко и непринужденно вычислит объем текста в битах, байтах и килобайтах. Для перевода в другие единицы измерения данных воспользуйтесь онлайн конвертером.

Информационный вес (объем) символа текста определяется для следующих кодировок:
Unicode UTF-8
Unicode UTF-16
ASCII, ANSI, Windows-1251

Текст

Символов 0

Символов без учета пробелов 0

Уникальных символов 0

Слов 0

Слов (буквенных) 0

Уникальных слов 0

Строк 0

Абзацев 0

Предложений 0

Средняя длина слова 0

Время чтения 0 сек

Букв 0

Русских букв 0

Латинских букв 0

Гласных букв 0

Согласных букв 0

Слогов 0

Цифр 0

Чисел 0

Пробелов 0

Остальных знаков 0

Знаков препинания 0

Объем текста (Unicode UTF-8) бит 0

Объем текста (Unicode UTF-8) байт 0

Объем текста (Unicode UTF-8) килобайт 0

Объем текста (Unicode UTF-16) бит 0

Объем текста (Unicode UTF-16) байт 0

Объем текста (Unicode UTF-16) килобайт 0

Объем текста (ASCII, ANSI, Windows-1251) бит 0

Объем текста (ASCII, ANSI, Windows-1251) байт 0

Объем текста (ASCII, ANSI, Windows-1251) килобайт 0

Почему на windows сохраняя текст блокноте перенос строки занимает – 4 байта в юникоде или 2 байта в анси?
Это историческое явление, которое берёт начало с дос, последовательность OD OA (nr ) в виндовс используются чтоб был единообразный вывод на терминал независимо консоль это или принтер. Но для вывода просто на консоль достаточно только n.

В юникоде есть символы которые весят 4 байта, например эмоджи: 🙃

×

Пожалуйста напишите с чем связна такая низкая оценка:

×

Для установки калькулятора на iPhone – просто добавьте страницу
«На главный экран»

Для установки калькулятора на Android – просто добавьте страницу
«На главный экран»

Is there some function which will tell me how many bytes does a string occupy in memory?

I need to set a size of a socket buffer in order to transfer the whole string at once.

asked Oct 25, 2010 at 9:20

Richard Knop's user avatar

Richard KnopRichard Knop

80.2k149 gold badges391 silver badges551 bronze badges

3

If it’s a Python 2.x str, get its len. If it’s a Python 3.x str (or a Python 2.x unicode), first encode to bytes (or a str, respectively) using your preferred encoding ('utf-8' is a good choice) and then get the len of the encoded bytes/str object.


For example, ASCII characters use 1 byte each:

>>> len("hello".encode("utf8"))
5

whereas Chinese ones use 3 bytes each:

>>> len("你好".encode("utf8"))
6

answered Oct 25, 2010 at 9:48

tzot's user avatar

2

import sys
sys.getsizeof(s)

# getsizeof(object, default) -> int
# Return the size of object in bytes.

But actually you need to know its represented length, so something like len(s) should be enough.

answered Oct 25, 2010 at 9:23

eumiro's user avatar

eumiroeumiro

205k34 gold badges297 silver badges261 bronze badges

8

Как оценить размер данных: краткий гайд

Время на прочтение
5 мин

Количество просмотров 5.3K

Оценка размера данных — это относительно простой навык, который одновременно: а) легко никогда не освоить; б) весьма полезен после того, как вы им овладели. Он может пригодиться при проектировании систем, в отладке сложной проблемы распределенной системы и, разумеется, при обсуждении архитектурных задач на собеседовании.

Автор Уилл Ларсон*, технический директор компании Calm, в своей статье признается, что никогда не был особенно хорош в «оценке». Поэтому он решил потратить несколько часов на развитие этого навыка, что со временем вылилось в текстовые заметки на эту тему. Под катом автор делится полезными правилами для оценки требуемого дискового пространства, а затем собирает фрагмент кода на SQLite3, чтобы продемонстрировать, как можно проверить результаты вашей «оценки».

*Обращаем ваше внимание, что позиция автора не всегда может совпадать с мнением МойОфис.


Килобайты (1000 байт) и Кибибайты (1024 байта)

Первое, что может привести к путанице в оценке требуемого пространства, это определение размера килобайта: 1024 байта или 1000 байт?

Правильный ответ состоит в том, что «килобайт» (КБ) составляет 1000 байт, а «кибибайт» (КиБ) — 1024 байта (прим. ред.: согласно терминологии, принятой в стандарте IEC 80000-13:2008). Подобное различие существует и в случае с другими единицами измерения, например: мегабайт (МБ, 1000^2) и мебибайт (МиБ, 1024^2), а также гигабайт (ГБ, 1000^3) и гибибайт (ГиБ, 1024^3).

Три ключевых момента, которые вам потребуется здесь учитывать, такие:

  • понимание как килобайтов, так и кибибайтов;

  • осознание и принятие того, что люди, с которыми вы взаимодействуете, могут быть не знакомы с семейством кибибайтов;

  • адаптация вашего подхода к той информации, с которой эти люди знакомы. Как известно, в реальной жизни нет баллов за техническую правильность.

Размер UTF-8, целые числа и т. д.

Хотя существует множество типов данных, с которыми полезно ознакомиться, наиболее распространенными из них являются:

  • Символы UTF-8. Кодируются в 1-4 байта. Следует ли вам оценивать требуемое пространство в 1, 2, 3 или 4 байта, зависит от того, что вы кодируете. Например, если вы кодируете только значения ASCII, достаточно 1 байта. Самое главное — уметь объяснить свою логику. Например, сказать, что в самом консервативном случае вы используете 4 байта на символ, — вполне обосновано.

    Взяв за основу размеры UTF-8, вы можете оценить размер строки, набора символов, текста или других подобных полей. Точные накладные расходы этих полей будут сильно различаться в зависимости от конкретной технологии, используемой для хранения данных.

  • Целочисленные данные. Их размер зависит от максимального значения, которое вам требуется сохранить, однако значением с хорошей точностью является 4 байта, которое можно взять за основу. Если вы хотите быть более точным, выясните максимальный размер целого числа: затем вы можете определить количество килобайт, необходимых для его представления с помощью вычисления:

maxRepresentableIntegerInNBytes(N) = 2 ^ (N bytes * 8 bits) - 1

Например, наибольшее число, которое можно представить в 2 байтах, равно:

2 ^ (2 bytes * 8 bits) - 1 = 65535
  • Числа с плавающей запятой. Обычно хранятся в 4 байтах.

  • Логические значения. Часто представляются как 1-байтовые целые числа (например, в MySQL).

  • Перечисления. Часто представляются как 2-байтовые целые числа (например, в MySQL).

  • Datetimes. Часто представлены в 5 байтах (например, в MySQL).

Вооружившись этими правилами, давайте попрактикуемся в оценке размера базы данных. Представим, что наша база данных включает 10 000 человек. Мы отслеживаем возраст и имя каждого человека. Средняя длина имени составляет 25 символов, а максимальный возраст — 125 лет. Сколько пространства нам потребуется?

bytesPerName = 25 characters * 4 bytes = 100 bytes
bytesPerAge = 1 byte  # because 2^(1 bytes * 8bits) = 255
bytesPerRow = 100 bytes + 1 byte
totalBytes = 101 bytes * 10,000 rows
totalKiloBytes = (101 * 10000) / 1000          # 1,100 kB
totalMegaBytes = (101 * 10000) / (1000 * 1000)   # 1.1 MB

Видим, что для хранения этих данных необходимо 1,1 МБ.

Альтернативный результат составляет 0,96 МиБ, и рассчитан он так:

(101 * 10000) / (1024 * 1024)  # 0.96 MiB

Теперь вы можете оценить размер наборов данных.

Индексы, репликация и т. д.

Существует разница между теоретической и фактической стоимостью хранения данных в базе. Возможно, вы используете инструмент на основе реплик, такой как MongoDB или Cassandra, который хранит три копии каждого фрагмента данных. Возможно, вы используете первично-вторичную систему репликации, в которой хранятся две копии каждой части данных. Влияние хранилища здесь довольно легко определить (соответственно, в 3 или 2 раза больше базовой стоимости).

Индексы предлагают классический компромисс между дополнительным хранилищем и сокращением времени запросов, но точная стоимость их хранения зависит от специфики самих индексов. Вот простой подход к расчету размера индексов: определите размер столбцов, включенных в индекс, умножьте его на количество проиндексированных строк и добавьте полученный результат к базовым затратам на хранение самих данных. Если вы создаете индекс, включающий каждое поле, общая стоимость хранения примерно удваивается.

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

Проверка с помощью SQLite3

Хорошая новость: проверить размер данных относительно легко. Это мы сейчас и сделаем, используя Python и SQLite3. Начнем с воссоздания приведенной выше оценки из 10 000 строк, каждая из которых содержит имя из 25 символов и возраст.

import uuid
import random
import sqlite3

def generate_users(path, rows):
    db = sqlite3.connect(path)
    cursor = db.cursor()
    cursor.execute("drop table if exists users")
    cursor.execute("create table users (name, age)")
    for i in range(rows):
        name = str(uuid.uuid4())[:25]
        age = random.randint(0, 125)
        cursor.execute("insert into users values (?, ?)", (name, age))
    db.commit()
    db.close()

if __name__ == "__main__":
    generate_users("users.db", 10000)

Ранее мы оценили это в 0,96 МиБ, но, запустив этот скрипт, я вижу другой размер — 344 КиБ, чуть более трети ожидаемого пространства. Немного отладив наш расчет мы видим, что мы предполагали 4 байта на символ, но имена, которые мы генерируем (усеченные UUID4 ), все являются символами ascii, поэтому на самом деле требуется 1 байт на символ. Давайте переоценим значение на основе этого:

bytesPerName = 25 characters * 1 byte = 25 bytes
bytesPerAge = 1 byte
bytesPerRow = 26 bytes
totalKibiBytes = (26 * 10,000) / 1024  # 245 KIB

Что ж, это довольно близко — если учитывать некоторые накладные расходы, которые, безусловно, есть. Например, SQLite3 открыто создает столбец rowid для использования в качестве первичного ключа, который представляет собой 64-битное целое число, для представления которого требуется 4 байта. Если мы добавим эти 4 байта к нашей предыдущей оценке в 26 байт на строку, то получим предполагаемый размер 293 КиБ, что достаточно близко к нашей оценке.

***

В заключение приведу ряд важных вопросов, на которые можно ответить с помощью успешной оценки дискового пространства:

  • Поместятся ли те или иные данные в памяти?

  • Поместятся ли они на одном сервере с SSD?

  • Нужно ли разбивать эти данные на множество серверов? Если да, то на какое количество?

  • Может ли тот или иной индекс поместиться на одном сервере?

  • Если нет, то как правильно разбить индекс?

  • И т.д. и т.п.

Я углубился в оценку размера данных не так давно, и все еще продолжаю удивляться тому, насколько эффективно этот подход может сузить для вас круг возможных решений в различных задачах.

Калькулятор считает, сколько байт занимает введенный текст.

Результат выдается сразу в двух кодировках: UTF-8/cp1251/KOI8/CP866 и UTF-16. В UTF-16 текст занимает в два раза больше места.

Введите текст (любой набор символов) *

Текст

Укажите символы, которые следует убрать из текста

Исключить символы

Регистр букв (для уникальных слов и букв)

Учитывать регистр букв

Выберите информацию, которую хотите получить

Задачи

* – обязательно заполнить

Обратите внимание на другие текстовые калькуляторы: https://calcon.ru/category/text/

Добавить комментарий