【问题标题】:How to get the number of characters in a std::string?如何获取 std::string 中的字符数?
【发布时间】:2010-10-28 16:01:58
【问题描述】:

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

【问题讨论】:

  • 你在处理什么样的字符串?标准::字符串?字符串?以空结尾的字符串?
  • 最简单的方法是 for 循环遍历它并自己计算字符。

标签: c++ string stdstring string-length


【解决方案1】:
string foo;
... foo.length() ...

.length 和 .size 是同义词,我只是觉得“length”这个词稍微清楚一点。

【讨论】:

  • size() 不鼓励,因为我记得听说在某些实现中它会返回“length() + 1”(因为它包含空终止符)。因此,只需使用 length(),因为它更简洁、更便携。
  • @LaQuet,如果您没有使用符合标准的编译器或 STL 实现,您需要担心的事情更多。
  • @Nelson 不应该是标准 C++ 字符串不以空值结尾的情况。但是,当使用 c_str() 进行强制转换时,它会将空字节添加到末尾。
【解决方案2】:
std::string str("a string");
std::cout << str.size() << std::endl;

【讨论】:

    【解决方案3】:

    如果您使用的是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 likes to call them,当它们有一个尾随 NULL 时),只需取消对第一个字符的引用。

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

    【讨论】:

    • 有谁会使用 Pascal 风格的字符串?
    • length() 返回的不是字节数,不是字符数?
    • 对于 std::string,它是同样的事情(除非您存储可变长度编码,或使用 std::string 存储多字节字符)。如果您这样做,您将不会从 std 库中获得任何帮助,因此您也可以处理自己的 strlen 滚动。对于 wstring、u16string 和 u32string,它返回字符数,而不是字节数。 (再次附带条件,如果您在其中任何一个中使用可变长度编码,您将不得不推出自己的 strlen)。
    • 提及返回类型会增加这个评价很高的答案的价值:std::size_t
    • @Eclipse +1 for f***ed 字符串
    【解决方案4】:

    在处理 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;
    }
    

    输出:

    6
    6
    6
    6
    

    【讨论】:

    • 请注意,您可以通过使用 #include 而不是已弃用的 #include 来避免编译器警告(在某些 C++ 编译器中)
    • 您的示例仅使用 ASCII。你介意为 Unicode 字符更新它吗?尤其是 32 位的,比如?
    【解决方案5】:

    对于一个实际的字符串对象:

    yourstring.length();
    

    yourstring.size();
    

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

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

        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 库已将这一切抽象为他们称之为 string access shims 的东西,它可用于从任何类型获取字符串长度(和其他方面)。因此,对于上述所有内容(包括非标准库的),使用相同的函数stlsoft::c_str_len()This article 描述了它是如何工作的,因为它并不是完全显而易见或容易的。

        【讨论】:

        • 哪一个适合?等32位字符?
        【解决方案8】:

        如果你使用 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);
        

        【讨论】:

          【解决方案9】:

          这可能是输入字符串并找到其长度的最简单方法。

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

          【讨论】:

          • 你认为 count(string) 有什么作用,而 string::length() 没有呢?除了不必要地复制字符串,如果字符串中有超过 20 亿个字符,则返回负值。
          【解决方案10】:

          获取字符串长度而不用关心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;
          }
          

          【讨论】:

            【解决方案11】:

            在 C++ std::string 中,length() 和 size() 方法为您提供字节数,不一定是字符数!。 与 c-Style 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
            

            【讨论】:

              【解决方案12】:

              对于 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-10-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-01-25
                • 2018-11-24
                • 2019-06-02
                • 2017-01-07
                相关资源
                最近更新 更多