Як отримати кількість символів у рядку std ::?


112

Як я можу отримати кількість символів у рядку в C ++?


1
З якими струнами ви маєте справу? std :: string? cstring? нульовий завершений рядок?
Стів Роу

Найбільш дурним способом було б провести цикл і порахувати персонажів самостійно.
Krythic

Відповіді:


177

Якщо ви використовуєте std::string, зателефонуйте length():

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

Якщо ви використовуєте c-string, дзвоніть strlen().

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

Або, якщо вам подобається використовувати рядки в стилі Паскаль (або f ***** рядки, як Джоел Спольський любить називати їх, коли у них є кінцевий NULL), просто перенесіть перший символ.

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

7
Хто з їх розуму міг би використовувати рядки в стилі Паскаль?
Xarn

17
не length () не повертає кількість байтів, а не кількість символів?

2
Для std :: string - це те ж саме (якщо ви не зберігаєте кодування змінної довжини або використовуєте std :: string для зберігання багатобайтових символів). Якщо ви робите це, ви не збираєтеся отримувати багато допомоги з бібліотеки std, тож також можете впоратися з прокруткою власного strlen. Для wstring, u16string та u32string він повертає кількість символів, а не байти. (Знову з умовою, що якщо ви використовуєте кодування змінної довжини в будь-якому з них, вам доведеться прокрутити свій власний струн).
Затемнення

4
Це додало б значення цього високо оцінив відповідь згадати тип повертається значення : std::size_t.
chux

3
@Eclipse +1 для рядків f *** ed
Snađошƒаӽ

23

У роботі з рядками C ++ (std :: string), ви шукаєте довжину () або розмір () . Обидва повинні надавати вам однакове значення. Однак, маючи справу з рядками C-Style, ви б використовували 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* - багатобайтовий рядок у стилі С
  2. const wchar_t* - широкий рядок у стилі С
  3. std::string - "стандартний" багатобайтовий рядок
  4. std::wstring - "стандартна" широка струна

Для 3 і 4 можна використовувати .size()або .length()методи.

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

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

Існують і інші типи рядків у нестандартних бібліотеках C ++, такі як MFC CString, ATL CComBSTR, ACEACE_CString тощо, з такими методами, як .GetLength()тощо. Я не можу пригадати їхню специфіку з самого верху голови.

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


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

4

Для Unicode

Тут було розглянуто кілька відповідей, які .length()дають неправильні результати з багатобайтовими символами, але є 11 відповідей, і жодна з них не дала рішення.

Справа Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚

Перш за все, важливо знати, що ви маєте на увазі під «довжиною». Для мотивуючого прикладу розглянемо рядок "Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚" (зауважте, що деякі мови, зокрема тайська, насправді використовують комбінуючі діакритичні позначки, тому це не просто корисно для 15-річних мемів, але, очевидно, це найважливіший випадок використання) . Припустимо, він закодований у UTF-8 . Є три способи говорити про довжину цього рядка:

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

Пошук довжин за допомогою ICU

Існують класи 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, у вас є про що більше турбуватися.
страгер

2
@Nelson, що не повинно бути таким, як у стандартних C ++ Strings, не скасовуються на нуль. Однак при кастингу за допомогою c_str () він додасть нульовий байт до кінця.
Джон Т



2

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

Для більшості символів для друку 7bit-ASCII це те саме значення, але для символів, які не є 7bit-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) робить цей рядок :: length () ні? Крім того, зайве копіювання рядка та повернення від'ємного значення, якщо в рядку більше 2 мільярдів символів.
Затемнення

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.