วิธีรับจำนวนอักขระใน std :: string?


112

ฉันจะรับจำนวนอักขระในสตริงใน C ++ ได้อย่างไร


1
คุณกำลังจัดการกับสตริงประเภทใด มาตรฐาน :: สตริง? CString? สตริงสิ้นสุดที่ว่างเปล่า?
Steve Rowe

วิธีพิสูจน์ความโง่เขลาที่สุดคือการวนซ้ำและนับอักขระด้วยตัวเอง
Krythic

คำตอบ:


177

หากคุณใช้std::stringโทรlength():

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

หากคุณใช้ c-string โทรstrlen().

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

หรือถ้าคุณชอบใช้สตริงแบบปาสคาล (หรือสตริง f ***** ตามที่ Joel Spolsky ชอบเรียกเมื่อมีค่า NULL ต่อท้าย) เพียงแค่กำหนดค่าอักขระตัวแรก

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

7
ใครในความคิดที่ถูกต้องของพวกเขาที่จะใช้สตริงสไตล์ปาสกาล?
Xarn

17
ไม่ length () ส่งคืนจำนวนไบต์ไม่ใช่จำนวนอักขระ?

2
สำหรับสตริง std :: ก็เหมือนกัน (เว้นแต่คุณจะจัดเก็บการเข้ารหัสความยาวตัวแปรหรือใช้ std :: string เพื่อเก็บอักขระแบบหลายไบต์) หากคุณทำเช่นนั้นคุณจะไม่ได้รับความช่วยเหลืออะไรมากจากไลบรารีมาตรฐานดังนั้นคุณจึงสามารถจัดการกับ strlen ของคุณเองได้เช่นกัน สำหรับ wstring, u16string และ u32string จะส่งกลับจำนวนอักขระแทนที่จะเป็นไบต์ (อีกครั้งกับเงื่อนไขที่ว่าหากคุณใช้การเข้ารหัสแบบความยาวผันแปรในสิ่งเหล่านี้คุณจะต้องม้วน strlen ของคุณเอง)
คราส

4
std::size_tมันจะเพิ่มมูลค่าให้กับคำตอบนี้การจัดอันดับสูงที่จะกล่าวถึงชนิดของสิ่งตอบแทน:
chux - คืนสถานะ Monica

3
@Eclipse +1 สำหรับf *** ed strings
Sнаđошƒаӽ

23

เมื่อจัดการกับ c ++ สตริง (มาตรฐาน :: สตริง) คุณกำลังมองหายาว ()หรือขนาด () ทั้งสองควรให้คุณค่าเดียวกัน แต่เมื่อต้องรับมือกับสาย 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

5
โปรดทราบว่าคุณสามารถหลีกเลี่ยงคำเตือนของคอมไพเลอร์ (ในคอมไพเลอร์ C ++ บางตัว) โดยใช้ #include <cstring> แทน #include <string.h> ที่เลิกใช้แล้ว
Colin

1
ตัวอย่างของคุณใช้ ASCII คุณช่วยอัปเดตสำหรับอักขระ Unicode ด้วยหรือไม่? โดยเฉพาะอย่างยิ่ง 32 บิตเช่น𝄞
Thomas Weller

17

ขึ้นอยู่กับประเภทสตริงที่คุณกำลังพูดถึง สตริงมีหลายประเภท:

  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's CString, ATL's CComBSTR, ACE ACE_CStringเป็นต้นโดยมีวิธีการเช่น.GetLength()และอื่น ๆ ฉันจำข้อมูลเฉพาะของพวกเขาไม่ได้ทั้งหมดจากด้านบนของหัว

STLSoftห้องสมุดได้ใจลอยนี้ออกทั้งหมดกับสิ่งที่พวกเขาเรียกshims เข้าถึงสตริงซึ่งสามารถนำมาใช้เพื่อให้ได้ความยาวสาย (และด้านอื่น ๆ ) จากชนิดใด ๆ ดังนั้นสำหรับทั้งหมดข้างต้น (รวมถึงคนที่ห้องสมุดที่ไม่ได้มาตรฐาน) stlsoft::c_str_len()โดยใช้ฟังก์ชั่นเดียวกัน บทความนี้อธิบายถึงวิธีการทำงานทั้งหมดเนื่องจากไม่ใช่เรื่องที่ชัดเจนหรือเข้าใจง่ายทั้งหมด


1
ตัวใดเหมาะกับอักขระ 32 บิตเช่น𝄞?
Thomas Weller

4

สำหรับ 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

มีคลาส C ++ สำหรับ ICU แต่ต้องแปลงเป็น 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


3

หากคุณใช้สตริงสไตล์ C แบบเก่าแทนที่จะเป็นสตริงสไตล์ STL ที่ใหม่กว่ามีstrlenฟังก์ชันในไลบรารีเวลาทำงานของ C:

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

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

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

.length และ .size มีความหมายเหมือนกันฉันแค่คิดว่า "length" เป็นคำที่ชัดเจนกว่าเล็กน้อย


size () ท้อใจเพราะฉันจำได้ว่าเคยได้ยินมาว่าในการนำไปใช้งานบางอย่างมันจะส่งคืน "length () + 1" (เพราะรวมถึงตัวยุติที่เป็นโมฆะ) ดังนั้นเพียงใช้ length () เนื่องจากสะอาดและพกพาสะดวกกว่า

1
@LaQuet หากคุณไม่ได้ใช้คอมไพเลอร์ที่เป็นไปตามมาตรฐานหรือการใช้งาน STL คุณมีสิ่งที่ต้องกังวลเพิ่มเติม
strager

2
@ เนลสันที่ไม่ควรเป็นเช่นนั้นเนื่องจากสตริง C ++ มาตรฐานจะไม่สิ้นสุดด้วยค่าว่าง อย่างไรก็ตามเมื่อแคสต์ด้วย c_str () มันจะเพิ่ม null ไบต์ต่อท้าย
John T



2

ใน C ++ std :: string เมธอด length () และ size () จะให้จำนวนไบต์และไม่จำเป็นต้องเป็นจำนวนอักขระ! เหมือนกับฟังก์ชัน c-Style sizeof ()!

สำหรับอักขระ 7 บิต ASCII ที่สามารถพิมพ์ได้ส่วนใหญ่จะเป็นค่าเดียวกัน แต่สำหรับอักขระที่ไม่ใช่ 7 บิต - ASCII จะไม่แน่นอน ดูตัวอย่างต่อไปนี้เพื่อให้ได้ผลลัพธ์จริง (64 บิตลินุกซ์)

ไม่มีฟังก์ชัน 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

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

}

4
อะไรที่คุณคิดว่า count (string) นั้น string :: length () ไม่? นอกเหนือจากการทำสำเนาสตริงเพิ่มเติมโดยไม่จำเป็นและส่งคืนค่าลบหากมีอักขระมากกว่า 2 พันล้านตัวในสตริง
Eclipse

0

วิธีที่ง่ายที่สุดในการรับความยาวของสตริงโดยไม่ต้องกังวลกับเนมสเปซมาตรฐานมีดังนี้

สตริงที่มี / ไม่มีช่องว่าง

#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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.