วิธีการแปลงตัวเลขเป็นสตริงและในทางกลับกันใน C ++


120

เนื่องจากคำถามนี้ถูกถามทุกสัปดาห์คำถามที่พบบ่อยนี้อาจช่วยผู้ใช้จำนวนมากได้

  • วิธีการแปลงจำนวนเต็มเป็นสตริงใน C ++

  • วิธีการแปลงสตริงเป็นจำนวนเต็มใน C ++

  • วิธีการแปลงตัวเลขทศนิยมเป็นสตริงใน C ++

  • วิธีการแปลงสตริงเป็นตัวเลขทศนิยมใน C ++


สำหรับการแปลงเช่นนี้ฉันมีบุ๊กมาร์กconverttypes.com
Firzok Nadeem

คำตอบ:


129

อัปเดตสำหรับ C ++ 11

ตามC++11มาตรฐานการแปลงสตริงเป็นตัวเลขและในทางกลับกันถูกสร้างขึ้นในไลบรารีมาตรฐาน มีฟังก์ชันทั้งหมดต่อไปนี้อยู่ใน<string>(ตามย่อหน้าที่ 21.5)

สตริงเป็นตัวเลข

float              stof(const string& str, size_t *idx = 0);
double             stod(const string& str, size_t *idx = 0);
long double        stold(const string& str, size_t *idx = 0);
int                stoi(const string& str, size_t *idx = 0, int base = 10);
long               stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long      stoul(const string& str, size_t *idx = 0, int base = 10);
long long          stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);

แต่ละรายการใช้สตริงเป็นอินพุตและจะพยายามแปลงเป็นตัวเลข หากไม่สามารถสร้างหมายเลขที่ถูกต้องได้ตัวอย่างเช่นเนื่องจากไม่มีข้อมูลตัวเลขหรือตัวเลขอยู่นอกช่วงสำหรับประเภทข้อยกเว้นจะถูกโยนทิ้ง ( std::invalid_argumentหรือstd::out_of_range)

หากการแปลงสำเร็จและ idxไม่ได้0, idxจะมีดัชนีของตัวอักษรตัวแรกที่ไม่ได้ใช้สำหรับการถอดรหัส นี่อาจเป็นดัชนีหลังอักขระสุดท้าย

สุดท้ายประเภทอินทิกรัลอนุญาตให้ระบุฐานสำหรับตัวเลขที่มีขนาดใหญ่กว่า 9 จะถือว่าตัวอักษร ( a=10จนถึงz=35) คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับการจัดรูปแบบที่แน่นอนที่สามารถแยกวิเคราะห์ที่นี่สำหรับจำนวนจุดลอยตัว , ลงนามจำนวนเต็มและจำนวนเต็มไม่ได้ลงนาม

สุดท้ายสำหรับแต่ละฟังก์ชันยังมีโอเวอร์โหลดที่ยอมรับไฟล์ std::wstringเนื่องจากเป็นพารามิเตอร์แรก

ตัวเลขเป็นสตริง

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

สิ่งเหล่านี้ตรงไปตรงมามากขึ้นคุณส่งประเภทตัวเลขที่เหมาะสมและคุณจะได้รับสตริงคืน สำหรับตัวเลือกการจัดรูปแบบคุณควรกลับไปที่ตัวเลือกสตริง C ++ 03 และใช้ตัวปรับแต่งกระแสตามที่อธิบายไว้ในคำตอบอื่น ๆ ที่นี่

ตามที่ระบุไว้ในความคิดเห็นฟังก์ชันเหล่านี้ถอยกลับไปเป็นค่าความแม่นยำของแมนทิสซาเริ่มต้นซึ่งน่าจะไม่ใช่ความแม่นยำสูงสุด หากต้องการความแม่นยำมากขึ้นสำหรับแอปพลิเคชันของคุณควรกลับไปใช้ขั้นตอนการจัดรูปแบบสตริงอื่น ๆ

นอกจากนี้ยังมีฟังก์ชั่นที่คล้ายกันกำหนดที่มีชื่อเหล่านี้จะกลับมาเป็นto_wstringstd::wstring


3
std::to_stringสูญเสียความแม่นยำอย่างมากสำหรับประเภทจุดลอยตัว ตัวอย่างเช่นdouble f = 23.4323897462387526; std::string f_str = std::to_string(f);ส่งคืนสตริง 23.432390 ทำให้ไม่สามารถเดินทางไปกลับค่าทศนิยมโดยใช้ฟังก์ชันเหล่านี้ได้
fun4jimmy

@ fun4jimmy นี่เป็นข้อ จำกัด ที่กำหนดโดยมาตรฐานหรือการใช้งานเฉพาะหรือไม่? จะเพิ่มคำตอบให้. ไม่ใช่ว่าการลอยข้ามเชือกเป็นความคิดที่ดีเลยทีเดียว
KillianDS

c ++มาตรฐานกล่าวว่า " ผลตอบแทนที่แต่ละฟังก์ชันส่งกลับวัตถุสตริงถือเป็นตัวแทนของตัวละครของมูลค่าของอาร์กิวเมนต์ที่จะถูกสร้างขึ้นโดยการเรียกsprintf(buf, fmt, val)กับระบุรูปแบบของ'% d' , 'u%' , '% ld' , " % lu " , "% lld " , "% llu " , "% f " , "% f "หรือ"% Lf "ตามลำดับซึ่งbufกำหนดบัฟเฟอร์อักขระภายในที่มีขนาดเพียงพอ " ฉันดูC99 แล้วมาตรฐานสำหรับprintfแล้วและฉันคิดว่าจำนวนตำแหน่งทศนิยมขึ้นอยู่กับ#define DECIMAL_DIGในลอย h.
fun4jimmy

บรูซดอว์สันมีบทความที่ดีบางอย่างเกี่ยวกับสิ่งที่มีความแม่นยำเป็นสิ่งจำเป็นสำหรับรอบสะดุดหมายเลขจุดลอยอยู่บนเขาบล็อก
fun4jimmy

2
ฟังก์ชันทั้งหมดเหล่านี้ได้รับผลกระทบจากโลแคลส่วนกลางซึ่งอาจทำให้เกิดปัญหาได้หากคุณใช้ไลบรารีและโดยเฉพาะอย่างยิ่งหากใช้เธรด ดูคำถามของฉันที่นี่: stackoverflow.com/questions/31977457/…
ระบุ

87

วิธีการแปลงตัวเลขเป็นสตริงใน C ++ 03

  1. อย่าใช้itoaหรือitofฟังก์ชั่นเพราะพวกเขาจะไม่ได้มาตรฐานและดังนั้นจึงไม่พกพา
  2. ใช้สตรีมสตริง

     #include <sstream>  //include this to use string streams
     #include <string> 
    
    int main()
    {    
        int number = 1234;
    
        std::ostringstream ostr; //output string stream
        ostr << number; //use the string stream just like cout,
        //except the stream prints not to stdout but to a string.
    
        std::string theNumberString = ostr.str(); //the str() function of the stream 
        //returns the string.
    
        //now  theNumberString is "1234"  
    }

    โปรดทราบว่าคุณสามารถใช้สตรีมสตริงเพื่อแปลงตัวเลขทศนิยมเป็นสตริงและยังจัดรูปแบบสตริงได้ตามที่คุณต้องการเช่นเดียวกับ cout

    std::ostringstream ostr;
    float f = 1.2;
    int i = 3;
    ostr << f << " + " i << " = " << f + i;   
    std::string s = ostr.str();
    //now s is "1.2 + 3 = 4.2" 

    คุณสามารถใช้ปั่นกระแสเช่นstd::endl, std::hexและฟังก์ชั่นstd::setw(), std::setprecision()ฯลฯ กับกระแสสตริงในตรงลักษณะเดียวกันเช่นเดียวกับcout

    อย่าสับสน กับstd::ostringstream std::ostrstreamหลังเลิกใช้งานแล้ว

  3. ใช้เพิ่มคำศัพท์หล่อ หากคุณไม่คุ้นเคยกับการเร่งความเร็วคุณควรเริ่มต้นด้วยไลบรารีขนาดเล็กเช่น lexical_cast นี้ ดาวน์โหลดและติดตั้งเพิ่มและเอกสารไปที่นี่ แม้ว่าการบูสต์จะไม่ได้อยู่ในไลบรารีบูสต์ C ++ มาตรฐานหลาย ๆ ไลบรารีก็ได้รับมาตรฐานในที่สุดและบูสต์ได้รับการพิจารณาอย่างกว้างขวางว่าเป็นไลบรารี C ++ ที่ดีที่สุด

    Lexical cast ใช้สตรีมที่อยู่ด้านล่างดังนั้นโดยพื้นฐานแล้วตัวเลือกนี้จะเหมือนกับตัวเลือกก่อนหน้าเพียงแค่ verbose น้อยลง

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       float f = 1.2;
       int i = 42;
       std::string sf = boost::lexical_cast<std::string>(f); //sf is "1.2"
       std::string si = boost::lexical_cast<std::string>(i); //sf is "42"
    }

วิธีการแปลงสตริงเป็นตัวเลขใน C ++ 03

  1. ตัวเลือกที่มีน้ำหนักเบาที่สุดซึ่งสืบทอดมาจาก C คือฟังก์ชันatoi(สำหรับจำนวนเต็ม (ตามตัวอักษรถึงจำนวนเต็ม)) และatof(สำหรับค่าทศนิยม (เรียงตามตัวอักษรถึงลอย)) ฟังก์ชันเหล่านี้ใช้สตริงสไตล์ C เป็นอาร์กิวเมนต์ ( const char *) ดังนั้นการใช้งานจึงอาจถือได้ว่าเป็นการปฏิบัติ C ++ ที่ไม่ดีนัก cplusplus.com มีเอกสารที่เข้าใจง่ายทั้งatoiและatofรวมถึงวิธีการทำงานในกรณีที่ข้อมูลป้อนไม่ถูกต้อง อย่างไรก็ตามลิงก์มีข้อผิดพลาดตามมาตรฐานหากหมายเลขอินพุตมีขนาดใหญ่เกินไปที่จะพอดีกับประเภทเป้าหมายพฤติกรรมจะไม่ได้กำหนด

    #include <cstdlib> //the standard C library header
    #include <string>
    int main()
    {
        std::string si = "12";
        std::string sf = "1.2";
        int i = atoi(si.c_str()); //the c_str() function "converts" 
        double f = atof(sf.c_str()); //std::string to const char*
    }
  2. ใช้สตรีมสตริง (สตรีมสตริงอินพุตเวลานี้istringstream) อีกครั้ง istringstream ใช้เช่นเดียวกับcin. อีกครั้งไม่สร้างความสับสนให้กับistringstream istrstreamหลังเลิกใช้งานแล้ว

    #include <sstream>
    #include <string>
    int main()
    {
       std::string inputString = "1234 12.3 44";
       std::istringstream istr(inputString);
       int i1, i2;
       float f;
       istr >> i1 >> f >> i2;
       //i1 is 1234, f is 12.3, i2 is 44  
    }
  3. ใช้เพิ่มคำศัพท์หล่อ

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       std::string sf = "42.2"; 
       std::string si = "42";
       float f = boost::lexical_cast<float>(sf); //f is 42.2
       int i = boost::lexical_cast<int>(si);  //i is 42
    }       

    ในกรณีที่อินพุตไม่ถูกต้องให้lexical_castเว้นประเภทboost::bad_lexical_cast


4
เอกสาร cplusplus สำหรับatoiไม่ดีมันไม่ถูกต้อง ไม่ได้กล่าวถึงว่าหากไม่สามารถแสดงค่าตัวเลขของสตริงได้แสดงintว่าพฤติกรรมนั้นไม่ได้กำหนดไว้ มันบอกว่าแทนที่จะยึดค่านอกช่วงไว้ที่INT_MAX/ INT_MINซึ่งฉันไม่พบใน C ++ 03 หรือ C89 สำหรับอินพุตที่ไม่น่าเชื่อถือ / ไม่ได้รับการยืนยันหรือเมื่อจัดการในฐานที่สตรีมไม่รองรับคุณจำเป็นต้องstrtolมีซึ่งกำหนดลักษณะการทำงานของข้อผิดพลาด และความคิดเห็นที่คล้ายกันสำหรับatof/ strtod.
Steve Jessop

2
cplusplus.com ผิดเกี่ยวกับ "atoi" มันบอกเกี่ยวกับค่าที่ส่งคืน "หากไม่สามารถดำเนินการแปลงที่ถูกต้องได้ระบบจะส่งคืนค่าเป็นศูนย์หากค่าที่ถูกต้องอยู่นอกช่วงของค่าที่แสดงได้ INT_MAX หรือ INT_MIN จะถูกส่งกลับ" แต่ข้อมูลจำเพาะระบุว่า "หาก ไม่สามารถแสดงมูลค่าของผลลัพธ์ได้พฤติกรรมนั้นไม่ได้รับการแก้ไข " และ "ยกเว้นพฤติกรรมที่เกิดข้อผิดพลาดจะเทียบเท่ากับ(int)strtol(nptr, (char **)NULL, 10)ฟังก์ชัน atoi [... ] จะคืนค่าที่แปลงแล้ว" cplusplus.com เป็นแหล่งข้อมูลที่ไม่ดีอย่างไม่น่าเชื่อสำหรับผู้เริ่มต้น
Johannes Schaub - litb

istr >> i1 >> f >> i2;พลาดการตรวจสอบความสำเร็จ
sbi

4
อาจต้องการเพิ่มstd::to_string
Pubby

1
@ArmenTsirunyan: +10 จากจุดสิ้นสุดของฉันหนึ่งในคำตอบที่ดีที่สุดที่ฉันเคยเห็นในเชิงลึกเกินไป ขอบคุณสำหรับคำตอบ.
Abhineet

4

ใน C ++ 17 ฟังก์ชั่นใหม่มาตรฐาน :: to_charsและมาตรฐาน :: from_charsได้ถูกนำเสนอในส่วนหัวcharconv

std :: to_chars เป็นโลแคลไม่ขึ้นอยู่กับการจัดสรรและไม่ขว้างปา

นโยบายการจัดรูปแบบชุดย่อยที่ใช้โดยไลบรารีอื่น (เช่น std :: sprintf) มีให้เพียงเล็กน้อยเท่านั้น

จากมาตรฐาน :: to_charsเดียวกันสำหรับมาตรฐาน :: from_chars

การรับประกันว่า std :: from_chars สามารถกู้คืนค่าทศนิยมทุกค่าที่จัดรูปแบบโดย to_chars อย่างแน่นอนจะมีให้ก็ต่อเมื่อฟังก์ชันทั้งสองมาจากการใช้งานเดียวกัน

 // See en.cppreference.com for more information, including format control.
#include <cstdio>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <charconv>

using Type =  /* Any fundamental type */ ;
std::size_t buffer_size = /* ... */ ;

[[noreturn]] void report_and_exit(int ret, const char *output) noexcept 
{
    std::printf("%s\n", output);
    std::exit(ret);
}
void check(const std::errc &ec) noexcept
{
    if (ec ==  std::errc::value_too_large)
        report_and_exit(1, "Failed");
}
int main() {
    char buffer[buffer_size];        
    Type val_to_be_converted, result_of_converted_back;

    auto result1 = std::to_chars(buffer, buffer + buffer_size,  val_to_be_converted);
    check(result1.ec);
    *result1.ptr = '\0';

    auto result2 = std::from_chars(buffer, result1.ptr, result_of_converted_back);
    check(result2.ec);

    assert(val_to_be_converted == result_of_converted_back);
    report_and_exit(0, buffer);
}

แม้ว่าคอมไพเลอร์จะไม่ได้ใช้งานอย่างสมบูรณ์ แต่ก็จะถูกนำไปใช้อย่างแน่นอน


0

ฉันขโมยคลาสที่สะดวกสบายนี้จากที่ไหนสักแห่งที่ StackOverflow เพื่อแปลงสิ่งที่สตรีมเป็นสตริงได้:

// make_string
class make_string {
public:
  template <typename T>
  make_string& operator<<( T const & val ) {
    buffer_ << val;
    return *this;
  }
  operator std::string() const {
    return buffer_.str();
  }
private:
  std::ostringstream buffer_;
};

แล้วคุณใช้เป็น;

string str = make_string() << 6 << 8 << "hello";

ดีทีเดียว!

นอกจากนี้ฉันยังใช้ฟังก์ชั่นนี้เพื่อแปลงสตริงเป็นอะไรก็ได้ที่สตรีมได้แม้ว่ามันจะไม่ปลอดภัยเท่าไหร่หากคุณพยายามแยกวิเคราะห์สตริงที่ไม่มีตัวเลข (และมันไม่ฉลาดเท่าคนสุดท้ายด้วย)

// parse_string
template <typename RETURN_TYPE, typename STRING_TYPE>
RETURN_TYPE parse_string(const STRING_TYPE& str) {
  std::stringstream buf;
  buf << str;
  RETURN_TYPE val;
  buf >> val;
  return val;
}

ใช้เป็น:

int x = parse_string<int>("78");

คุณอาจต้องการเวอร์ชันสำหรับ wstrings


5
นี่คือสิ่งที่ boost :: lexical_cast ทำ และบูสต์ทำในรูปแบบทั่วไปมากขึ้น
Armen Tsirunyan

จริงฉันอ่านคำตอบแรกและไม่เห็นการเพิ่ม :: lexical_casts
Viktor Sehr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.