¿Cómo obtener el número de caracteres en un std :: string?

112

¿Cómo debo obtener la cantidad de caracteres en una cadena en C ++?

Elliot
fuente
1
¿Con qué tipo de cadenas estás tratando? std :: cadena? ¿cuerda C? cadena terminada en nulo?
Steve Rowe
La forma más infalible sería recorrerlo y contar los caracteres usted mismo.
Krythic

Respuestas:

177

Si está usando un std::string, llame a length():

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

Si está usando una c-string, llame strlen().

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

O, si le gusta usar cadenas de estilo Pascal (o cadenas de mierda como a Joel Spolsky le gusta llamarlas cuando tienen un NULL al final), simplemente elimine la referencia al primer carácter.

const char *str = "\005hello";
std::cout << str + 1 << ":" << *str;
// Outputs "hello:5"
Eclipse
fuente
7
¿Quién en su sano juicio usaría cuerdas estilo Pascal?
Xarn
17
¿no devuelve length () el número de bytes, no el número de caracteres?
2
Para un std :: string, es lo mismo (a menos que esté almacenando una codificación de longitud variable o usando un std :: string para almacenar caracteres de varios bytes). Si está haciendo eso, no obtendrá mucha ayuda con nada de la biblioteca estándar, por lo que también puede manejar su propio strlen. Para wstring, u16string y u32string, devuelve el número de caracteres, en lugar de bytes. (Nuevamente con la condición de que si está utilizando una codificación de longitud variable en cualquiera de ellos, tendrá que lanzar su propio strlen).
Eclipse
4
Se añadiría valor a esta respuesta de alta calificación mencionar el tipo de retorno: std::size_t.
chux - Reincorporar a Monica
3
@Eclipse +1 para f *** ed strings
Sнаđошƒаӽ
23

Cuando se trata de cadenas de C ++ (std :: string), busca length () o size () . Ambos deberían proporcionarle el mismo valor. Sin embargo, cuando se trata de cadenas de estilo C, debería utilizar 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;
}

Salida:

6
6
6
6
John T
fuente
5
Tenga en cuenta que puede evitar las advertencias del compilador (en ciertos compiladores de C ++) usando #include <cstring> en lugar del obsoleto #include <string.h>
Colin
1
Tus ejemplos solo usan ASCII. ¿Le importaría actualizarlo también para caracteres Unicode? Especialmente los de 32 bits como 𝄞
Thomas Weller
17

Depende del tipo de cadena del que estés hablando. Hay muchos tipos de cadenas:

  1. const char* - una cadena multibyte estilo C
  2. const wchar_t* - una cuerda ancha de estilo C
  3. std::string - una cadena multibyte "estándar"
  4. std::wstring - una cuerda ancha "estándar"

Para 3 y 4, puede usar los métodos .size()o .length().

Para 1, puede usar strlen(), pero debe asegurarse de que la variable de cadena no sea NULL (=== 0)

Para 2, puede usar wcslen(), pero debe asegurarse de que la variable de cadena no sea NULL (=== 0)

Hay otros tipos de cadenas en bibliotecas de C ++ no estándar, como MFC CString, ATL CComBSTR, ACE ACE_CString, etc., con métodos como .GetLength(), etc. No puedo recordar los detalles de todos ellos de la parte superior de mi cabeza.

El STLSoft bibliotecas de han resumido todo esto con lo que llaman shims de acceso a cadenas , que se pueden usar para obtener la longitud de la cadena (y otros aspectos) de cualquier tipo. Entonces, para todo lo anterior (incluidas las bibliotecas no estándar), use la misma función stlsoft::c_str_len(). Este artículo describe cómo funciona todo, ya que no es del todo obvio o fácil.

dcw
fuente
1
¿Cuál es adecuado para caracteres de 32 bits como 𝄞?
Thomas Weller
4

Para Unicode

Varias respuestas aquí han abordado que .length() dan resultados incorrectos con caracteres multibyte, pero hay 11 respuestas y ninguna de ellas ha proporcionado una solución.

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

En primer lugar, es importante saber a qué te refieres con "longitud". Para un ejemplo motivador, considere la cadena "Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪl̨͎̰̘͉̟ͤ̀̈̚͜g͕͔̤͖̟̒͝ͅo̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚" (tenga en cuenta que algunos idiomas, especialmente el tailandés, en realidad usan signos diacríticos combinados, por lo que esto no solo es útil para los memes de 15 años, pero obviamente ese es el caso de uso más importante) . Suponga que está codificado en UTF-8 . Hay 3 formas en las que podemos hablar sobre la longitud de esta cadena:

95 bytes

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 puntos de código

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 grafemas

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

Encontrar las longitudes usando UCI

Hay clases C ++ para ICU, pero requieren conversión a UTF-16. Puede utilizar los tipos de C y las macros directamente para obtener compatibilidad con 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̵̡̡̼͚̐ͯ̅ͪ̆ͣ̚");
}

Esto imprime:

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 envuelve ICU y podría proporcionar una interfaz más agradable. Sin embargo, aún requiere conversión a / desde UTF-16.

Robert Fraser
fuente
3

Si está utilizando cadenas antiguas de estilo C en lugar de las cadenas de estilo STL más nuevas, existe la strlenfunción en la biblioteca de tiempo de ejecución de C:

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

si está usando std :: string, hay dos métodos comunes para eso:

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

si está usando la cadena de estilo C (usando char * o const char *) entonces puede usar:

const char *pStr = "Some String";
size_t Size = strlen(pStr);
Gal Goldman
fuente
2
string foo;
... foo.length() ...

.length y .size son sinónimos, creo que "length" es una palabra un poco más clara.

Alex Martelli
fuente
Se desaconseja size () porque recuerdo haber oído que en algunas implementaciones devolverá "length () + 1" (porque incluye el terminador nulo). Así que solo usa length () ya que es más limpio y más portátil.
1
@LaQuet, si no está utilizando un compilador compatible con los estándares o una implementación de STL, tiene más cosas de las que preocuparse.
extraño
2
@Nelson, ese no debería ser el caso, ya que las cadenas de C ++ estándar no tienen terminación nula. Sin embargo, al lanzar con c_str () agregará el byte nulo al final.
John T
2
std::string str("a string");
std::cout << str.size() << std::endl;
StefanB
fuente
2

para un objeto de cadena real:

yourstring.length();

o

yourstring.size();
Luke Schafer
fuente
2

En C ++ std :: string, el método length () y size () le da el número de bytes, y no necesariamente el número de caracteres. ¡Lo mismo con la función de tamaño de estilo c ()!

Para la mayoría de los caracteres ASCII de 7 bits imprimibles, este es el mismo valor, pero para los caracteres que no son ASCII de 7 bits definitivamente no lo es. Vea el siguiente ejemplo para obtener resultados reales (Linux de 64 bits).

No existe una función simple de c / c ++ que realmente pueda contar el número de caracteres. Por cierto, todo esto depende de la implementación y puede ser diferente en otros entornos (compilador, win 16/32, linux, embedded, ...)

Vea el siguiente ejemplo:

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

El resultado del ejemplo es este:

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
Hape Entner
fuente
0

Podría ser la forma más fácil de ingresar una cadena y encontrar su longitud.

// 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());

}
usuario2808359
fuente
4
¿Qué es lo que crees que count (string) hace que string :: length () no? Además de hacer innecesariamente una copia adicional de la cadena y devolver un valor negativo si hay más de 2 mil millones de caracteres en la cadena.
Eclipse
0

La forma más sencilla de obtener la longitud de la cadena sin preocuparse por el espacio de nombres estándar es la siguiente

cadena con / sin espacios

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

cadena sin espacios

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