Jak uzyskać liczbę znaków w std :: string?


112

Jak uzyskać liczbę znaków w ciągu w C ++?


1
Z jakimi sznurkami masz do czynienia? std :: string? Ciąg c? ciąg zakończony wartością null?
Steve Rowe

Najgłupszym sposobem byłoby zapętlenie go i samodzielne policzenie znaków.
Krythic

Odpowiedzi:


177

Jeśli używasz std::string, zadzwoń length():

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

Jeśli używasz ciągu c, wywołaj strlen().

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

Lub, jeśli przypadkiem lubisz używać ciągów w stylu Pascala (lub pieprzonych ciągów, jak lubi je nazywać Joel Spolsky, gdy mają na końcu NULL), po prostu dereferencjonuj pierwszy znak.

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

7
Kto przy zdrowych zmysłach używałby strun w stylu Pascala?
Xarn

17
nie length () zwraca liczby bajtów, a nie liczby znaków?

2
W przypadku std :: string jest to to samo (chyba że przechowujesz kodowanie o zmiennej długości lub używasz std :: string do przechowywania znaków wielobajtowych). Jeśli to robisz, nie uzyskasz zbytniej pomocy z niczego z biblioteki standardowej, więc możesz również poradzić sobie z toczeniem własnego strlen. W przypadku wstring, u16string i u32string zwraca liczbę znaków, a nie bajtów. (Ponownie z zastrzeżeniem, że jeśli używasz kodowania o zmiennej długości w którymkolwiek z nich, będziesz musiał skręcić swój własny strlen).
Eclipse

4
Byłoby dodać wartość do tego wysoko oceniane odpowiedź wspomnieć Zwraca typ: std::size_t.
chux - Przywróć Monikę

3
@Eclipse +1 for f *** ed strings
Sнаđошƒаӽ

23

Kiedy mamy do czynienia z ciągami znaków C ++ (std :: string), szukasz length () lub size () . Oba powinny zapewniać tę samą wartość. Jednak w przypadku ciągów w stylu C należy użyć 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;
}

Wynik:

6
6
6
6

5
Zauważ, że możesz uniknąć ostrzeżeń kompilatora (w niektórych kompilatorach C ++), używając #include <cstring> zamiast przestarzałego #include <string.h>
Colin

1
Twoje przykłady używają po prostu ASCII. Czy mógłbyś zaktualizować go również dla znaków Unicode? Zwłaszcza te 32-bitowe, takie jak 𝄞
Thomas Weller

17

Zależy to od rodzaju łańcucha, o którym mówisz. Istnieje wiele rodzajów ciągów:

  1. const char* - ciąg wielobajtowy w stylu C.
  2. const wchar_t* - szeroki sznurek w stylu C.
  3. std::string - „standardowy” ciąg wielobajtowy
  4. std::wstring - „standardowy” szeroki sznurek

W przypadku 3 i 4 możesz użyć metod .size()lub .length().

Dla 1 możesz użyć strlen(), ale musisz upewnić się, że zmienna łańcuchowa nie ma wartości NULL (=== 0)

W przypadku 2 możesz użyć wcslen(), ale musisz upewnić się, że zmienna łańcuchowa nie ma wartości NULL (=== 0)

Istnieją inne typy ciągów w niestandardowych bibliotekach C ++, takich jak MFC CString, ATL CComBSTR, ACE ACE_CStringi tak dalej, z metodami takimi jak .GetLength()i tak dalej. Nie mogę sobie przypomnieć szczegółów ich wszystkich od samego początku.

W STLSoft biblioteki zostały oderwane to wszystko się z tym, co nazywają podkładek ciąg dostępu , które mogą być wykorzystane, aby uzyskać długość ciągu (i inne aspekty) z dowolnego typu. Więc dla wszystkich powyższych (w tym niestandardowych bibliotek) przy użyciu tej samej funkcji stlsoft::c_str_len(). W tym artykule opisano, jak to wszystko działa, ponieważ nie jest to całkowicie oczywiste ani łatwe.


1
Który jest odpowiedni dla znaków 32-bitowych, takich jak 𝄞?
Thomas Weller

4

W przypadku Unicode

Kilka odpowiedzi tutaj rozwiązało, które .length()dają nieprawidłowe wyniki ze znakami wielobajtowymi, ale jest 11 odpowiedzi i żadna z nich nie zapewniła rozwiązania.

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

Przede wszystkim ważne jest, aby wiedzieć, co rozumiesz przez „długość”. Aby uzyskać motywujący przykład, rozważ ciąg „Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚” (zauważ, że niektóre języki, zwłaszcza tajski, używają kombinacji znaków diakrytycznych, więc nie jest to przydatne tylko w przypadku memów 15-letnich, ale oczywiście jest to najważniejszy przypadek użycia) . Załóżmy, że jest zakodowany w UTF-8 . Istnieją 3 sposoby, w jakie możemy mówić o długości tego ciągu:

95 bajtów

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 punktów kodowych

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 grafemów

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

Znajdowanie długości za pomocą ICU

Istnieją klasy C ++ dla ICU, ale wymagają one konwersji na UTF-16. Możesz użyć typów C i makr bezpośrednio, aby uzyskać obsługę 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̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚");
}

To drukuje:

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 otacza ICU i może zapewnić ładniejszy interfejs. Jednak nadal wymaga konwersji do / z UTF-16.


3

Jeśli używasz starego ciągu w stylu C zamiast nowszych ciągów w stylu STL, strlenw bibliotece wykonawczej C znajduje się funkcja:

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

3

jeśli używasz std :: string, istnieją dwie typowe metody:

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

jeśli używasz łańcucha w stylu C (używając char * lub const char *), możesz użyć:

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

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

.length i .size to synonimy, po prostu myślę, że „długość” jest nieco jaśniejszym słowem.


Funkcja size () jest odradzana, ponieważ pamiętam, że słyszałem, że w niektórych implementacjach zwróci wartość „length () + 1” (ponieważ zawiera terminator zerowy). Więc po prostu użyj length (), ponieważ jest czystszy i bardziej przenośny.

1
@LaQuet, Jeśli nie używasz kompilatora zgodnego ze standardami lub implementacji STL, masz więcej powodów do zmartwień.
strager

2
@Nelson, który nie powinien mieć miejsca, ponieważ w przypadku standardowych ciągów C ++ nie ma zakończenia zerowego. Jednak podczas rzutowania za pomocą c_str () doda bajt null na końcu.
John T

2
std::string str("a string");
std::cout << str.size() << std::endl;


2

W C ++ std :: string metody length () i size () podają liczbę bajtów, a niekoniecznie liczbę znaków!. To samo z funkcją sizeof () w stylu c!

W przypadku większości drukowalnych znaków 7-bitowego ASCII jest to ta sama wartość, ale w przypadku znaków innych niż 7-bitowe ASCII zdecydowanie nie. Zobacz poniższy przykład, aby uzyskać prawdziwe wyniki (64-bitowy system Linux).

Nie ma prostej funkcji c / c ++, która może naprawdę policzyć liczbę znaków. Nawiasem mówiąc, wszystkie te rzeczy zależą od implementacji i mogą różnić się w innych środowiskach (kompilator, win 16/32, linux, embedded, ...)

Zobacz następujący przykład:

#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;
}

Wynik przykładu jest następujący:

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

To może być najłatwiejszy sposób na wprowadzenie łańcucha i znalezienie jego długości.

// 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
Jak myślisz, czego nie robi count (string), że string :: length () nie? Poza tym niepotrzebne tworzenie dodatkowej kopii ciągu i zwracanie wartości ujemnej, jeśli w ciągu jest więcej niż 2 miliardy znaków.
Eclipse

0

Najprostszy sposób uzyskania długości łańcucha bez przejmowania się standardową przestrzenią nazw jest następujący

ciąg z / bez spacji

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

ciąg bez spacji

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    cin>>str;
    cout<<"Length of given string is"<<str.length();
    return 0;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.