Как получить количество символов в std :: string?


112

Как мне узнать количество символов в строке на C ++?


1
С какими струнами вы имеете дело? std :: string? cstring? строка с завершающим нулем?
Стив Роу,

Самый надежный способ - перебрать его и самостоятельно подсчитать символы.
Krythic

Ответы:


177

Если вы используете A std::string, позвоните length():

std::string str = "hello";
std::cout << str << ":" << str.length();
// Outputs "hello:5"

Если вы используете c-строку, позвоните strlen().

const char *str = "hello";
std::cout << str << ":" << strlen(str);
// Outputs "hello:5"

Или, если вам нравится использовать строки в стиле Паскаля (или чертовы строки, как Джоэл Спольски любит называть их, когда они имеют завершающий NULL), просто разыменуйте первый символ.

const char *str = "\005hello";
std::cout << str + 1 << ":" << *str;
// Outputs "hello:5"

7
Кто в здравом уме стал бы использовать строки в стиле Паскаля?
Xarn 06

17
не length () возвращает количество байтов, а не количество символов?

2
Для std :: string это то же самое (если вы не храните кодировку переменной длины или не используете std :: string для хранения многобайтовых символов). Если вы это сделаете, вы не получите особой помощи ни с чем из библиотеки std, так что вы также можете справиться с прокруткой своего собственного strlen. Для wstring, u16string и u32string он возвращает количество символов, а не байтов. (Опять же с оговоркой, что если вы используете кодировку переменной длины в любом из них, вам придется свернуть свой собственный strlen).
Eclipse,

4
Это добавило бы значение этого высоко оценил ответ упомянуть тип возвращаемого значения : std::size_t.
chux

3
@Eclipse +1 за долбанные струны
Sнаđошƒаӽ

23

При работе со строками C ++ (std :: string) вы ищете length () или size () . Оба должны предоставить вам одинаковую ценность. Однако при работе со строками в стиле C вы должны использовать strlen () .

#include <iostream>
#include <string.h>

int main(int argc, char **argv)
{
   std::string str = "Hello!";
   const char *otherstr = "Hello!"; // C-Style string
   std::cout << str.size() << std::endl;
   std::cout << str.length() << std::endl;
   std::cout << strlen(otherstr) << std::endl; // C way for string length
   std::cout << strlen(str.c_str()) << std::endl; // convert C++ string to C-string then call strlen
   return 0;
}

Вывод:

6
6
6
6

5
Обратите внимание, что вы можете избежать предупреждений компилятора (в некоторых компиляторах C ++), используя #include <cstring> вместо устаревшего #include <string.h>
Колин

1
В ваших примерах просто используется ASCII. Не могли бы вы обновить его и для символов Unicode? Особенно 32-битные, такие как 𝄞
Томас Веллер

17

Это зависит от того, о каком типе струны вы говорите. Есть много типов струн:

  1. const char* - многобайтовая строка в стиле C
  2. const wchar_t* - широкая струна C-стиля
  3. std::string - «стандартная» многобайтовая строка
  4. std::wstring - «стандартная» широкая струна

Для 3 и 4 вы можете использовать .size()или.length() методы .

Для 1 вы можете использовать strlen() , но вы должны убедиться, что строковая переменная не равна NULL (=== 0)

Для 2 вы можете использовать wcslen(), но вы должны убедиться, что строковая переменная не равна NULL (=== 0)

В нестандартных библиотеках C ++ есть и другие строковые типы, такие как MFC CString, ATL CComBSTR, ACE ACE_CStringи т. Д., С такими методами, как .GetLength()и т. Д. Я не могу сразу вспомнить их специфику.

Библиотеки STLSoft абстрагировали все это с помощью так называемых прокладок доступа к строке , которые можно использовать для получения длины строки (и других аспектов) любого типа. Итак, для всего вышеперечисленного (включая нестандартные библиотечные) используется одна и та же функция stlsoft::c_str_len(). В этой статье описывается, как все это работает, поскольку это не совсем очевидно или просто.


1
Какой из них подходит для 32-битных символов, таких как 𝄞?
Томас Веллер

4

Для Юникода

Несколько ответов здесь были адресованы, что .length()дает неправильные результаты с многобайтовыми символами, но есть 11 ответов, и ни один из них не дал решения.

Дело Za̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo

Прежде всего, важно знать, что вы подразумеваете под словом «длина». В качестве мотивирующего примера рассмотрим строку «Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo» (обратите внимание, что в некоторых языках, особенно в тайском, на самом деле используются комбинированные диакритические знаки, так что это полезно не только для мемов 15-летней давности, но, очевидно, это наиболее важный вариант использования) . Предположим, он закодирован в UTF-8 . Есть 3 способа определить длину этой строки:

95 байт

00000000: 5acd a5cd accc becd 89cc b3cc ba61 cc92  Z............a..
00000010: cc92 cd8c cc8b cdaa ccb4 cd95 ccb2 6ccd  ..............l.
00000020: a4cc 80cc 9acc 88cd 9ccc a8cd 8ecc b0cc  ................
00000030: 98cd 89cc 9f67 cc92 cd9d cd85 cd95 cd94  .....g..........
00000040: cca4 cd96 cc9f 6fcc 90cd afcc 9acc 85cd  ......o.........
00000050: aacc 86cd a3cc a1cc b5cc a1cc bccd 9a    ...............

50 кодовых точек

LATIN CAPITAL LETTER Z
COMBINING LEFT ANGLE BELOW
COMBINING DOUBLE LOW LINE
COMBINING INVERTED BRIDGE BELOW
COMBINING LATIN SMALL LETTER I
COMBINING LATIN SMALL LETTER R
COMBINING VERTICAL TILDE
LATIN SMALL LETTER A
COMBINING TILDE OVERLAY
COMBINING RIGHT ARROWHEAD BELOW
COMBINING LOW LINE
COMBINING TURNED COMMA ABOVE
COMBINING TURNED COMMA ABOVE
COMBINING ALMOST EQUAL TO ABOVE
COMBINING DOUBLE ACUTE ACCENT
COMBINING LATIN SMALL LETTER H
LATIN SMALL LETTER L
COMBINING OGONEK
COMBINING UPWARDS ARROW BELOW
COMBINING TILDE BELOW
COMBINING LEFT TACK BELOW
COMBINING LEFT ANGLE BELOW
COMBINING PLUS SIGN BELOW
COMBINING LATIN SMALL LETTER E
COMBINING GRAVE ACCENT
COMBINING DIAERESIS
COMBINING LEFT ANGLE ABOVE
COMBINING DOUBLE BREVE BELOW
LATIN SMALL LETTER G
COMBINING RIGHT ARROWHEAD BELOW
COMBINING LEFT ARROWHEAD BELOW
COMBINING DIAERESIS BELOW
COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW
COMBINING PLUS SIGN BELOW
COMBINING TURNED COMMA ABOVE
COMBINING DOUBLE BREVE
COMBINING GREEK YPOGEGRAMMENI
LATIN SMALL LETTER O
COMBINING SHORT STROKE OVERLAY
COMBINING PALATALIZED HOOK BELOW
COMBINING PALATALIZED HOOK BELOW
COMBINING SEAGULL BELOW
COMBINING DOUBLE RING BELOW
COMBINING CANDRABINDU
COMBINING LATIN SMALL LETTER X
COMBINING OVERLINE
COMBINING LATIN SMALL LETTER H
COMBINING BREVE
COMBINING LATIN SMALL LETTER A
COMBINING LEFT ANGLE ABOVE

5 графем

Z with some s**t
a with some s**t
l with some s**t
g with some s**t
o with some s**t

Определение длины в отделении интенсивной терапии

Существуют классы C ++ для ICU, но они требуют преобразования в UTF-16. Вы можете использовать типы и макросы C напрямую, чтобы получить некоторую поддержку UTF-8:

#include <memory>
#include <iostream>
#include <unicode/utypes.h>
#include <unicode/ubrk.h>
#include <unicode/utext.h>

//
// C++ helpers so we can use RAII
//
// Note that ICU internally provides some C++ wrappers (such as BreakIterator), however these only seem to work
// for UTF-16 strings, and require transforming UTF-8 to UTF-16 before use.
// If you already have UTF-16 strings or can take the performance hit, you should probably use those instead of
// the C functions. See: http://icu-project.org/apiref/icu4c/
//
struct UTextDeleter { void operator()(UText* ptr) { utext_close(ptr); } };
struct UBreakIteratorDeleter { void operator()(UBreakIterator* ptr) { ubrk_close(ptr); } };
using PUText = std::unique_ptr<UText, UTextDeleter>;
using PUBreakIterator = std::unique_ptr<UBreakIterator, UBreakIteratorDeleter>;

void checkStatus(const UErrorCode status)
{
    if(U_FAILURE(status))
    {
        throw std::runtime_error(u_errorName(status));
    }
}

size_t countGraphemes(UText* text)
{
    // source for most of this: http://userguide.icu-project.org/strings/utext
    UErrorCode status = U_ZERO_ERROR;
    PUBreakIterator it(ubrk_open(UBRK_CHARACTER, "en_us", nullptr, 0, &status));
    checkStatus(status);
    ubrk_setUText(it.get(), text, &status);
    checkStatus(status);
    size_t charCount = 0;
    while(ubrk_next(it.get()) != UBRK_DONE)
    {
        ++charCount;
    }
    return charCount;
}

size_t countCodepoints(UText* text)
{
    size_t codepointCount = 0;
    while(UTEXT_NEXT32(text) != U_SENTINEL)
    {
        ++codepointCount;
    }
    // reset the index so we can use the structure again
    UTEXT_SETNATIVEINDEX(text, 0);
    return codepointCount;
}

void printStringInfo(const std::string& utf8)
{
    UErrorCode status = U_ZERO_ERROR;
    PUText text(utext_openUTF8(nullptr, utf8.data(), utf8.length(), &status));
    checkStatus(status);

    std::cout << "UTF-8 string (might look wrong if your console locale is different): " << utf8 << std::endl;
    std::cout << "Length (UTF-8 bytes): " << utf8.length() << std::endl;
    std::cout << "Length (UTF-8 codepoints): " << countCodepoints(text.get()) << std::endl;
    std::cout << "Length (graphemes): " << countGraphemes(text.get()) << std::endl;
    std::cout << std::endl;
}

void main(int argc, char** argv)
{
    printStringInfo(u8"Hello, world!");
    printStringInfo(u8"หวัดดีชาวโลก");
    printStringInfo(u8"\xF0\x9F\x90\xBF");
    printStringInfo(u8"Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚");
}

Это печатает:

UTF-8 string (might look wrong if your console locale is different): Hello, world!
Length (UTF-8 bytes): 13
Length (UTF-8 codepoints): 13
Length (graphemes): 13

UTF-8 string (might look wrong if your console locale is different): หวัดดีชาวโลก
Length (UTF-8 bytes): 36
Length (UTF-8 codepoints): 12
Length (graphemes): 10

UTF-8 string (might look wrong if your console locale is different): 🐿
Length (UTF-8 bytes): 4
Length (UTF-8 codepoints): 1
Length (graphemes): 1

UTF-8 string (might look wrong if your console locale is different): Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚
Length (UTF-8 bytes): 95
Length (UTF-8 codepoints): 50
Length (graphemes): 5

Boost.Locale обертывает ICU и может обеспечить более приятный интерфейс. Однако он по-прежнему требует преобразования в / из UTF-16.


3

Если вы используете старую строку в стиле C вместо более новых строк в стиле STL, strlenв библиотеке времени выполнения C есть функция:

const char* p = "Hello";
size_t n = strlen(p);

3

если вы используете std :: string, для этого есть два общих метода:

std::string Str("Some String");
size_t Size = 0;
Size = Str.size();
Size = Str.length();

если вы используете строку стиля C (используя char * или const char *), вы можете использовать:

const char *pStr = "Some String";
size_t Size = strlen(pStr);

2
string foo;
... foo.length() ...

.length и .size являются синонимами, я просто думаю, что «длина» - более ясное слово.


size () не рекомендуется, потому что я помню, что слышал, что в некоторых реализациях он будет возвращать «length () + 1» (потому что он включает нулевой терминатор). Так что просто используйте length (), так как он чище и портативнее.

1
@LaQuet, если вы не используете совместимый со стандартами компилятор или реализацию STL, вам есть о чем беспокоиться.
strager

2
@Nelson, этого не должно быть, поскольку стандартные строки C ++ не заканчиваются нулем. Однако при приведении с помощью c_str () он добавит нулевой байт в конец.
John T



2

В C ++ std :: string методы length () и size () дают вам количество байтов, а не обязательно количество символов!. То же самое с функцией sizeof () c-Style!

Для большинства печатаемых 7-битных символов ASCII это одно и то же значение, но для символов, не являющихся 7-битными ASCII, это определенно не так. См. Следующий пример, чтобы получить реальные результаты (64-разрядная версия Linux).

Не существует простой функции c / c ++, которая действительно могла бы подсчитать количество символов. Кстати, все это зависит от реализации и может отличаться в других средах (компилятор, win 16/32, linux, встроенный, ...)

См. Следующий пример:

#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

int main()
{
/* c-Style char Array */
const char * Test1 = "1234";
const char * Test2 = "ÄÖÜ€";
const char * Test3 = "αβγ𝄞";

/* c++ string object */
string sTest1 = "1234";
string sTest2 = "ÄÖÜ€";
string sTest3 = "αβγ𝄞";

printf("\r\nC Style Resluts:\r\n");
printf("Test1: %s, strlen(): %d\r\n",Test1, (int) strlen(Test1));
printf("Test2: %s, strlen(): %d\r\n",Test2, (int) strlen(Test2));
printf("Test3: %s, strlen(): %d\r\n",Test3, (int) strlen(Test3));

printf("\r\nC++ Style Resluts:\r\n");
cout << "Test1: " << sTest1 << ", Test1.size():  " <<sTest1.size() <<"  sTest1.length(): " << sTest1.length() << endl;
cout << "Test1: " << sTest2 << ", Test2.size():  " <<sTest2.size() <<"  sTest1.length(): " << sTest2.length() << endl;
cout << "Test1: " << sTest3 << ", Test3.size(): " <<sTest3.size() << "  sTest1.length(): " << sTest3.length() << endl;
return 0;
}

Результат примера таков:

C Style Results:
Test1: ABCD, strlen(): 4    
Test2: ÄÖÜ€, strlen(): 9
Test3: αβγ𝄞, strlen(): 10

C++ Style Results:
Test1: ABCD, sTest1.size():  4  sTest1.length(): 4
Test2: ÄÖÜ€, sTest2.size():  9  sTest2.length(): 9
Test3: αβγ𝄞, sTest3.size(): 10  sTest3.length(): 10

0

Это может быть самый простой способ ввести строку и найти ее длину.

// Finding length of a string in C++ 
#include<iostream>
#include<string>
using namespace std;

int count(string);

int main()
{
string str;
cout << "Enter a string: ";
getline(cin,str);
cout << "\nString: " << str << endl;
cout << count(str) << endl;

return 0;

}

int count(string s){
if(s == "")
  return 0;
if(s.length() == 1)
  return 1;
else
    return (s.length());

}

4
Что вы думаете, что count (string) не делает этого string :: length ()? Помимо ненужного создания дополнительной копии строки и возврата отрицательного значения, если в строке более 2 миллиардов символов.
Eclipse

0

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

строка с / без пробелов

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    getline(cin,str);
    cout<<"Length of given string is"<<str.length();
    return 0;
}

строка без пробелов

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    cin>>str;
    cout<<"Length of given string is"<<str.length();
    return 0;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.