如何获取std :: string中的字符数?

Ell*_*iot 109 c++ string stdstring string-length

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

Ecl*_*pse 171

如果你正在使用std::string,请致电length():

std::string str = "hello";
std::cout << str << ":" << str.length();
// Outputs "hello:5"
Run Code Online (Sandbox Code Playgroud)

如果您使用的是C字符串,请致电strlen().

const char *str = "hello";
std::cout << str << ":" << strlen(str);
// Outputs "hello:5"
Run Code Online (Sandbox Code Playgroud)

或者,如果您碰巧喜欢使用Pascal样式的字符串(或者像Joel Spolsky 喜欢在尾随NULL时调用它们的 f*****字符串),只需取消引用第一个字符.

const char *str = "\005hello";
std::cout << str + 1 << ":" << *str;
// Outputs "hello:5"
Run Code Online (Sandbox Code Playgroud)

  • 不是length()返回字节数,而不是字符数? (12认同)
  • 谁心智正常会使用Pascal风格的字符串? (7认同)
  • 它会为这个评价很高的答案增加价值,提到返回类型:`std :: size_t`. (4认同)
  • @Eclipse +1 for*f\***ed strings* (3认同)
  • 对于std :: string,它是相同的(除非您存储可变长度编码,或使用std :: string存储多字节字符).如果你这样做,你就不会从std库中获得任何帮助,所以你也可以处理你自己的strlen.对于wstring,u16string和u32string,它返回字符数而不是字节数.(同样附带条件是,如果你在其中任何一个中使用可变长度编码,你将不得不滚动自己的strlen). (2认同)

Joh*_*n T 21

处理C++字符串(std :: string)时,您正在寻找length()size().两者都应该为您提供相同的价值.但是在处理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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

6
6
6
6
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您可以使用#include <cstring>而不是弃用的#include <string.h>来避免编译器警告(在某些C++编译器中) (5认同)

dcw*_*dcw 16

这取决于你所谈论的字符串类型.有许多类型的字符串:

  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().本文将介绍它是如何工作的,因为它并非完全明显或简单.


Rob*_*ser 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    ...............
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

使用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????????????");
}
Run Code Online (Sandbox Code Playgroud)

这打印:

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
Run Code Online (Sandbox Code Playgroud)

Boost.Locale包装了 ICU,并可能提供更好的界面。但是,它仍然需要与 UTF-16 之间的转换。