122

我应该如何在 C++ 中获取字符串中的字符数?

4

12 回答 12

185

如果您使用的是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"

或者,如果您碰巧喜欢使用 Pascal 风格的字符串(或 f***** 字符串,因为 Joel Spolsky喜欢在它们有尾随 NULL 时调用它们),只需取消引用第一个字符。

const char *str = "\005hello";
std::cout << str + 1 << ":" << *str;
// Outputs "hello:5"
于 2009-05-25T04:50:47.560 回答
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
于 2009-05-25T04:51:00.460 回答
17

这取决于您正在谈论的字符串类型。字符串有很多种:

  1. const char*- C 风格的多字节字符串
  2. const wchar_t*- C 风格的宽字符串
  3. std::string- “标准”多字节字符串
  4. std::wstring- 一个“标准”宽字符串

对于 3 和 4,可以使用.size()or.length()方法。

对于 1,可以使用strlen(),但必须确保字符串变量不为 NULL (=== 0)

对于2,可以使用wcslen(),但必须保证字符串变量不为NULL(=== 0)

非标准 C++ 库中还有其他字符串类型,例如 MFC's CString、 ATL's CComBSTR、 ACE'sACE_CString等,具有诸如 等方法.GetLength()。我不记得他们的细节了。

STLSoft库用他们所谓的字符串访问垫片将这一切抽象出来,可用于从任何类型获取字符串长度(和其他方面)。因此,对于上述所有内容(包括非标准库的),使用相同的功能。本文描述了它是如何工作的,因为它并不完全显而易见或容易。stlsoft::c_str_len()

于 2009-05-25T06:39:24.247 回答
11

对于 Unicode

这里的几个答案已经解决.length()了使用多字节字符给出错误结果的问题,但是有 11 个答案并且没有一个提供解决方案。

Z͉̳̺ͥͬ̾a̴͕̲̒̒͌̋ͪ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

使用ICU查找长度

ICU 有 C++ 类,但它们需要转换为 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 进行转换。

于 2019-03-15T15:49:17.047 回答
3

如果您使用旧的 C 样式字符串而不是较新的 STL 样式字符串,则strlenC 运行时库中有该函数:

const char* p = "Hello";
size_t n = strlen(p);
于 2009-05-25T04:55:38.100 回答
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);
于 2009-05-25T06:44:02.897 回答
3

在 C++ std::string 中,length() 和 size() 方法为您提供字节数,而不一定是字符数!。 与 c 样式的 sizeof() 函数相同!

对于大多数可打印的 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
于 2018-05-20T08:09:57.690 回答
2
string foo;
... foo.length() ...

.length 和 .size 是同义词,我只是认为“长度”是一个更清晰的词。

于 2009-05-25T04:50:04.563 回答
2
std::string str("a string");
std::cout << str.size() << std::endl;
于 2009-05-25T04:50:08.090 回答
2

对于实际的字符串对象:

yourstring.length();

或者

yourstring.size();
于 2009-05-25T04:51:16.653 回答
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());

}
于 2013-09-28T16:50:17.353 回答
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;
}
于 2015-06-12T06:34:38.543 回答