ฉันจะแปลง std :: string เป็น int ได้อย่างไร


484

เพียงแค่มีคำถามด่วน ฉันดูรอบ ๆ อินเทอร์เน็ตเล็กน้อยและฉันพบวิธีแก้ปัญหาเล็กน้อย แต่ยังไม่มีวิธีแก้ปัญหาใด ๆ เลย ดูที่การแปลงสตริงเป็น int และฉันไม่ได้หมายถึงรหัส ASCII

สำหรับ run-down อย่างรวดเร็วเราถูกส่งผ่านในสมการเป็นสตริง เราต้องทำลายมันจัดรูปแบบให้ถูกต้องและแก้สมการเชิงเส้น ตอนนี้โดยบอกว่าฉันไม่สามารถแปลงสตริงเป็น int ได้

ฉันรู้ว่าสตริงจะอยู่ในรูปแบบ (-5) หรือ (25) เป็นต้นดังนั้นมันจึงเป็น int อย่างแน่นอน แต่เราจะแยกมันออกจากสตริงได้อย่างไร

วิธีหนึ่งที่ฉันคิดว่าใช้สำหรับ / วนรอบสตริงตรวจสอบตัวเลขแยกตัวเลขทั้งหมดหลังจากนั้นแล้วดูว่ามีผู้นำ '-' ถ้ามีคูณ int ด้วย - 1

ดูเหมือนว่าจะซับซ้อนกว่าเล็กน้อยสำหรับปัญหาเล็ก ๆ น้อย ๆ ความคิดใด ๆ


9
คุณเคยลองatoi()ไหม
i_am_jorf



7
@Chad ดังนั้นคุณแนะนำให้เขาใช้ไลบรารีทั้งหมดเพื่อให้บางสิ่งที่ภาษาสามารถทำได้กับไลบรารีมาตรฐานได้หรือไม่
Bojangles

6
@Brandon ถ้าคุณมีstd::string myStringและต้องการที่จะใช้แล้วคุณอยากจะบอกว่าatoi atoi(myString.c_str())
Robᵩ

คำตอบ:


726

ใน C ++ 11 มีฟังก์ชั่นแปลงใหม่ที่ดีจากstd::stringประเภทตัวเลข

ดังนั้นแทนที่จะ

atoi( str.c_str() )

คุณสามารถใช้ได้

std::stoi( str )

ที่เป็นหมายเลขของคุณเป็นstrstd::string

มีรุ่นสำหรับรสชาติของตัวเลข: long stol(string), float stof(string), double stod(string)... ดูhttp://en.cppreference.com/w/cpp/string/basic_string/stol


5
สำหรับปัญหาเกี่ยวกับมาตรฐาน :: Stoi เห็นstackoverflow.com/a/6154614/195527 : มันจะแปลงให้เป็นจำนวนเต็ม"11x" 11
สำเนาถึง

5
#include <stdlib.h> / * atoi * /
Ulad Kasach

4
@CC นั่นคือพฤติกรรมของ atoi: cplusplus.com/reference/cstdlib/atoi "สตริงสามารถมีอักขระเพิ่มเติมหลังจากที่สร้างตัวเลขจำนวนหนึ่งซึ่งจะถูกละเว้นและไม่มีผลกระทบต่อพฤติกรรมของฟังก์ชันนี้"
Tin Wizard

4
คุณต้องการอัปเดตคำตอบนี้ด้วยfrom_charsจาก C ++ 17 หรือไม่ stoiมันควรจะเป็นคำสั่งของขนาดได้เร็วกว่า
NathanOliver

stoiควรเป็นที่ต้องการ ดูทำไมฉันไม่ควรใช้ atoi ()
phuclv

57
std::istringstream ss(thestring);
ss >> thevalue;

หากต้องการแก้ไขอย่างสมบูรณ์คุณจะต้องตรวจสอบการตั้งค่าสถานะข้อผิดพลาด


2
นี้จะไม่แยกจาก-5 (-5)
นาวาซ

@Nawaz เป็นผู้อุปถัมภ์ที่นั่นจริง ๆ หรือเป็นเพียงว่า OP นำเสนอสตริงของเขาอย่างไร?
Winston Ewert

ฉันไม่รู้ ฉันแค่ชี้ให้เห็นข้อ จำกัด ของวิธีการ
นาวาซ

16
@Nawaz มันไม่สามารถทำงานกับอินพุต "WERWER" ได้ ฉันไม่คิดว่า parens นั้นเป็นส่วนหนึ่งของสายอักขระที่แท้จริงของเขาและฉันไม่คิดว่าข้อเท็จจริงที่ว่าฉันไม่ได้แยกมันจะเกี่ยวข้องกัน
Winston Ewert

4
@Nawaz โอเค ... ฉันไม่ได้ใช้คำนั้น แต่ฉันเห็นว่าคุณทำได้
Winston Ewert

44

ตัวเลือกที่เป็นไปได้อธิบายไว้ด้านล่าง:

1. ตัวเลือกแรก: sscanf ()

    #include <cstdio>
    #include <string>

        int i;
        float f;
        double d;
        std::string str;

        // string -> integer
        if(sscanf(str.c_str(), "%d", &i) != 1)
            // error management

        // string -> float
        if(sscanf(str.c_str(), "%f", &f) != 1)
            // error management

        // string -> double 
        if(sscanf(str.c_str(), "%lf", &d) != 1)
            // error management

นี่เป็นข้อผิดพลาด (แสดงโดย cppcheck) เนื่องจาก"scanf ที่ไม่มีขีด จำกัด ความกว้างของฟิลด์สามารถชนกับข้อมูลอินพุตจำนวนมากใน libc บางรุ่น" (ดูที่นี่และที่นี่ )

2. ตัวเลือกที่สอง: std :: sto * ()

    #include <iostream>
    #include <string>

        int i;
        float f;
        double d;
        std::string str;

        try {
            // string -> integer
            int i = std::stoi(str);

            // string -> float
            float f = std::stof(str);

            // string -> double 
            double d = std::stod(str);
        } catch (...) {
            // error management
        }   

โซลูชันนี้สั้นและสง่างาม แต่มีให้บริการเฉพาะบนคอมไพเลอร์ที่สอดคล้องกับ C ++ 11 เท่านั้น

3. ตัวเลือกที่สาม: sstreams

    #include <string>
    #include <sstream>

        int i;
        float f;
        double d;
        std::string str;

        // string -> integer
        std::istringstream ( str ) >> i;

        // string -> float
        std::istringstream ( str ) >> f;

        // string -> double 
        std::istringstream ( str ) >> d;

        // error management ??

อย่างไรก็ตามด้วยวิธีนี้ยากที่จะแยกแยะระหว่างอินพุตที่ไม่ดี (ดูที่นี่ )

4. ตัวเลือกที่สี่: เพิ่ม lexical_cast

    #include <boost/lexical_cast.hpp>
    #include <string>

        std::string str;

        try {
            int i = boost::lexical_cast<int>( str.c_str());
            float f = boost::lexical_cast<int>( str.c_str());
            double d = boost::lexical_cast<int>( str.c_str());
            } catch( boost::bad_lexical_cast const& ) {
                // Error management
        }

อย่างไรก็ตามนี่เป็นเพียงตัวปิดsstreamและเอกสารแนะนำให้ใช้sstreamสำหรับการจัดการข้อผิดพลาดที่ดีขึ้น (ดูที่นี่ )

5. ตัวเลือกที่ห้า: strto * ()

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

6. ตัวเลือกที่หก: Qt

    #include <QString>
    #include <string>

        bool ok;
        std::string;

        int i = QString::fromStdString(str).toInt(&ok);
        if (!ok)
            // Error management

        float f = QString::fromStdString(str).toFloat(&ok);
        if (!ok)
            // Error management 

        double d = QString::fromStdString(str).toDouble(&ok);
        if (!ok)
    // Error management     

สรุปผลการวิจัย

สรุปแล้วทางออกที่ดีที่สุดคือ C ++ 11 std::stoi()หรือเป็นตัวเลือกที่สองคือการใช้ไลบรารี Qt โซลูชันอื่นทั้งหมดไม่สนับสนุนหรือเป็นข้อบกพร่อง


แก้ไขแล้ว. ขอบคุณสำหรับการรายงาน
Claudio

สรุปที่สวยงามขอบคุณมาก ฉันขอแนะนำให้เพิ่มความคิดเห็นเริ่มต้นเพื่อแนะนำวิธีแก้ปัญหาขั้นสุดท้ายเพื่อให้เฉพาะผู้ที่สนใจในรายละเอียดอ่านต่อไปเท่านั้น?
luca

1
นี่ควรเป็นคำตอบที่ได้รับการยอมรับนอกจากนี้คุณลืม (หรือมากกว่านั้นควรเพิ่มเพราะมันเป็นคำตอบเก่า) from_chars
xception


9

แล้วBoost.Lexical_castล่ะ?

นี่คือตัวอย่างของพวกเขา:

ตัวอย่างต่อไปนี้ถือว่าอาร์กิวเมนต์บรรทัดคำสั่งเป็นลำดับของข้อมูลตัวเลข:

int main(int argc, char * argv[])
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;

    std::vector<short> args;

    while(*++argv)
    {
        try
        {
            args.push_back(lexical_cast<short>(*argv));
        }
        catch(bad_lexical_cast &)
        {
            args.push_back(0);
        }
    }
    ...
}

ลิงก์เสีย คุณช่วยแก้ไขได้ไหม
Yuchen Zhong

5

วิธีการแก้ปัญหาของฉันใช้ไม่ได้กับจำนวนเต็มลบ แต่จะดึงจำนวนเต็มบวกทั้งหมดจากข้อความอินพุตที่มีจำนวนเต็ม มันใช้ประโยชน์จากnumeric_onlyสถานที่:

int main() {
        int num;
        std::cin.imbue(std::locale(std::locale(), new numeric_only()));
        while ( std::cin >> num)
             std::cout << num << std::endl;
        return 0;
}

ข้อความที่ป้อน:

 the format (-5) or (25) etc... some text.. and then.. 7987...78hjh.hhjg9878

จำนวนเต็มเอาต์พุต:

 5
25
7987
78
9878

คลาสnumeric_onlyถูกกำหนดเป็น:

struct numeric_only: std::ctype<char> 
{
    numeric_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc[':'], std::ctype_base::digit);
        return &rc[0];
    }
};

การสาธิตออนไลน์สมบูรณ์: http://ideone.com/dRWSj


4

มันอาจจะเกินความเป็นไปได้นิดหน่อย แต่ก็ boost::lexical_cast<int>( theString )ควรที่จะทำงานให้ดี


พิมพ์ผิด มันควรจะง่าย ๆboost::lexical_cast<int>( theString )(ซึ่งtheStringเป็นชื่อของตัวแปรที่มีสตริงที่คุณต้องการแปลงเป็นint)
James Kanze

1

atoi เป็นฟังก์ชันในตัวที่แปลงสตริงเป็นจำนวนเต็มโดยสมมติว่าสตริงเริ่มต้นด้วยการแทนค่าจำนวนเต็ม

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/


เมื่อใดก็ตามที่คุณคิดถึงatoiให้ใช้strtolแทน
Ben Voigt

1

ใน Windows คุณสามารถใช้:

const std::wstring hex = L"0x13";
const std::wstring dec = L"19";

int ret;
if (StrToIntEx(hex.c_str(), STIF_SUPPORT_HEX, &ret)) {
    std::cout << ret << "\n";
}
if (StrToIntEx(dec.c_str(), STIF_SUPPORT_HEX, &ret)) {
    std::cout << ret << "\n";
}

strtol, stringstreamจำเป็นที่จะต้องระบุฐานถ้าคุณต้องการที่จะตีความ hexdecimal


1

มีคำตอบมากมายความเป็นไปได้มากมาย สิ่งที่ฉันหายไปนี่คือวิธีการสากลที่แปลงสตริงให้เป็นประเภท C ++ ที่ต่างกัน (แบบสั้น, แบบยาว, แบบยาว, แบบบูล, ... ) ฉันคิดวิธีแก้ปัญหาต่อไปนี้:

#include<sstream>
#include<exception>
#include<string>
#include<type_traits>

using namespace std;

template<typename T>
T toIntegralType(const string &str) {
    static_assert(is_integral<T>::value, "Integral type required.");
    T ret;
    stringstream ss(str);
    ss >> ret;
    if ( to_string(ret) != str)
        throw invalid_argument("Can't convert " + str);
    return ret;
}

นี่คือตัวอย่างการใช้งาน:

string str = "123";
int x = toIntegralType<int>(str); // x = 123

str = "123a";
x = toIntegralType<int>(str); // throws exception, because "123a" is not int

str = "1";
bool y = toIntegralType<bool>(str); // y is true
str = "0";
y = toIntegralType<bool>(str); // y is false
str = "00";
y = toIntegralType<bool>(str); // throws exception

ทำไมไม่เพียงแค่ใช้ตัวดำเนินการเอาต์พุตสตรีมเพื่อแปลงสตริงให้เป็นชนิดที่สมบูรณ์ นี่คือคำตอบ: สมมุติว่าสตริงมีค่าที่เกินขีด จำกัด สำหรับประเภทอินทิกรัลที่ต้องการ สำหรับการสอบบน Wndows 64 max int คือ 2147483647 เรามากำหนดสตริงให้กับค่า max int + 1: string str = "2147483648" ตอนนี้เมื่อแปลงสตริงเป็น int:

stringstream ss(str);
int x;
ss >> x;

x กลายเป็น 2147483647 สิ่งที่เป็นข้อผิดพลาดแน่นอน: สตริง "2147483648" ไม่ควรถูกแปลงเป็น int 2147483647 ฟังก์ชันที่ให้ไว้กับ InTegralType จะตรวจพบข้อผิดพลาดดังกล่าวและทำให้เกิดข้อยกเว้น


0

จากhttp://www.cplusplus.com/reference/string/stoi/

// stoi example
#include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  std::string str_dec = "2001, A Space Odyssey";
  std::string str_hex = "40c3";
  std::string str_bin = "-10010110001";
  std::string str_auto = "0x7f";

  std::string::size_type sz;   // alias of size_t

  int i_dec = std::stoi (str_dec,&sz);
  int i_hex = std::stoi (str_hex,nullptr,16);
  int i_bin = std::stoi (str_bin,nullptr,2);
  int i_auto = std::stoi (str_auto,nullptr,0);

  std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
  std::cout << str_hex << ": " << i_hex << '\n';
  std::cout << str_bin << ": " << i_bin << '\n';
  std::cout << str_auto << ": " << i_auto << '\n';

  return 0;
}

เอาท์พุท:

2544, A Space Odyssey: 2001 และ [, A Space Odyssey]

40c3: 16579

-10010110001: -1201

0x7f: 127



0
ll toll(string a){
    ll ret=0;
    bool minus=false;
    for(auto i:a){
        if(i=='-'){ minus=true; continue; }
        ret*=10;
        ret+=(i-'0');
    } if(minus) ret*=-1;
    return ret;
    # ll is defined as, #define ll long long int
    # usage: ll a = toll(string("-1234"));
}

0

ในการแปลงจากการแสดงสตริงเป็นค่าจำนวนเต็มเราสามารถใช้ std :: stringstream

ถ้าค่าที่แปลงอยู่นอกช่วงสำหรับประเภทข้อมูลจำนวนเต็มจะส่งกลับค่า INT_MIN หรือ INT_MAX

นอกจากนี้หากค่าสตริงไม่สามารถแสดงว่าเป็นชนิดข้อมูล int ที่ถูกต้องจะส่งคืนค่า 0

#include 
#include 
#include 

int main() {

    std::string x = "50";
    int y;
    std::istringstream(x) >> y;
    std::cout << y << '\n';
    return 0;
}

ผลลัพธ์: 50

ตามเอาต์พุตข้างต้นเราสามารถเห็นมันแปลงจากหมายเลขสตริงเป็นจำนวนเต็ม

แหล่งที่มาและอื่น ๆ ที่สตริงถึง int c ++


-2

รุ่นหนึ่งบรรทัด: long n = strtol(s.c_str(), NULL, base); .

( sคือสตริงและbaseเป็นintเช่น 2, 8, 10, 16)

คุณสามารถดูได้ที่ลิงค์นี้strtolสำหรับรายละเอียดเพิ่มเติมของ


แนวคิดหลักคือการใช้strtolฟังก์ชั่นซึ่งรวมอยู่ในcstdlibฟังก์ชั่นซึ่งรวมอยู่ใน

เนื่องจากstrtolจัดการกับcharอาเรย์เท่านั้นเราจึงต้องแปลงstringเป็นcharอาเรย์ คุณสามารถอ้างอิงถึงลิงค์นี้นี้

ตัวอย่าง:

#include <iostream>
#include <string>   // string type
#include <bitset>   // bitset type used in the output

int main(){
    s = "1111000001011010";
    long t = strtol(s.c_str(), NULL, 2); // 2 is the base which parse the string

    cout << s << endl;
    cout << t << endl;
    cout << hex << t << endl;
    cout << bitset<16> (t) << endl;

    return 0;
}

ซึ่งจะเอาท์พุท:

1111000001011010
61530
f05a
1111000001011010

-3

มีอีกวิธีที่ง่าย: สมมติว่าคุณมีตัวละครที่ชอบ c='4'นั้นคุณสามารถทำหนึ่งในขั้นตอนเหล่านี้:

1st: int q

q=(int) c ; (q is now 52 in ascii table ) . q=q-48; remember that adding 48 to digits is their ascii code .

วิธีที่สอง:

q=c-'0'; the same , character '0' means 48


1
คำถามคือเกี่ยวกับการแปลงจากstringไปintมากกว่าจากการchar string
Yuchen Zhong

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