stringstream ทำอะไรได้บ้าง?


107

ฉันพยายามเรียนรู้ C ++ ตั้งแต่เมื่อวานและกำลังใช้เอกสารนี้: http://www.cplusplus.com/files/tutorial.pdf (หน้า 32) ฉันพบรหัสในเอกสารและฉันเรียกใช้ ฉันลองป้อน Rs 5.5 สำหรับราคาและจำนวนเต็มสำหรับปริมาณและผลลัพธ์เป็น 0 ฉันลองป้อน 5.5 และ 6 และเอาต์พุตถูกต้อง

// stringstreams
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main () 
{ 
  string mystr; 
  float price = 0; 
  int quantity = 0; 

  cout << "Enter price: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> price; 
  cout << "Enter quantity: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> quantity; 
  cout << "Total price: " << price*quantity << endl; 
  return 0; 
}

คำถาม: คำสั่ง mystring ทำหน้าที่อะไร? อ้างจากเอกสาร:

"ในตัวอย่างนี้เราได้รับค่าตัวเลขจากอินพุตมาตรฐานทางอ้อมแทนที่จะแยกค่าตัวเลขโดยตรงจากอินพุตมาตรฐานเราจะได้เส้นจากอินพุตมาตรฐาน (cin) ไปยังสตริงอ็อบเจกต์ (mystr) จากนั้นเราแยกจำนวนเต็ม ค่าจากสตริงนี้เป็นตัวแปรประเภท int (ปริมาณ) "

ความประทับใจของฉันคือฟังก์ชันจะเข้ามาเป็นส่วนหนึ่งของสตริงและใช้เป็นอินพุต

(ฉันไม่รู้ว่าจะถามคำถามที่นี่ได้อย่างไรฉันยังใหม่กับการเขียนโปรแกรม) ขอบคุณ


19
ตัวอย่างนี้ค่อนข้างแปลกฉันไม่เคยเห็นstringstreamแบบนั้นมาก่อน ฉันมักจะโหลดบรรทัดแปลงแล้วแยกตามส่วนอย่างไรก็ตามสิ่งนี้มีข้อได้เปรียบเล็กน้อยที่นี่เนื่องจากcin เป็นสตรีมอินพุตอยู่แล้ว ... ดังนั้นcin >> price >> quantity;จะง่ายกว่ามาก นั่นเป็นเหตุผลที่ดีที่จะไม่ใช้แบบฝึกหัดของ cplusplus.com
Bartek Banachewicz

6
ตลกดีที่บทช่วยสอนนั้นเป็นการเปิดรับ C ++ ครั้งแรกของฉัน ในการมองย้อนกลับไปมันค่อนข้างแย่และไม่สมบูรณ์ ฉันขอแนะนำหนังสือดีๆแทน
jrok

@BartekBanachewicz บางทีพวกเขาอาจจะต้องสร้างตัวอย่างเพื่อแสดงวิธีการstringstreamทำงาน มันเป็นสิ่งที่แปลกประหลาดอาจเป็นเรื่องที่ไม่ดีก็ได้ =) แต่มันแสดงให้เห็นว่าคุณสามารถใช้สตริงเป็นสตรีมได้
luk32

หากไม่ใช่การแนะนำการใช้งานขั้นสูงมากกว่าstringstreamนั้นก็เป็นตัวอย่างที่ผิดแน่นอน และแม้ว่าจะเป็นเช่นนั้นก็ควรเขียนให้แตกต่างกัน
j_kubik

1
@trojansdestroy คุณไม่สามารถเข้าใจ stringstream ได้หากไม่เข้าใจว่ามันมีพื้นฐานมาจากอะไรดังนั้นฉันจึงไม่เห็นว่าการอ่านบทช่วยสอนช่วยในเรื่องนั้นได้อย่างไร
Bartek Banachewicz

คำตอบ:


163

บางครั้งมันสะดวกมากที่จะใช้ stringstream เพื่อแปลงระหว่างสตริงและประเภทตัวเลขอื่น ๆ ลักษณะการใช้งานstringstreamคล้ายกับการใช้งานiostreamดังนั้นจึงไม่เป็นภาระในการเรียนรู้

Stringstreams สามารถใช้เพื่ออ่านสตริงและเขียนข้อมูลลงในสตริง ส่วนใหญ่ทำงานร่วมกับบัฟเฟอร์สตริง แต่ไม่มีช่อง I / O จริง

ฟังก์ชันสมาชิกพื้นฐานของคลาสสตริงสตรีมคือ

  • str()ซึ่งส่งคืนเนื้อหาของบัฟเฟอร์ในประเภทสตริง

  • str(string)ซึ่งตั้งค่าเนื้อหาของบัฟเฟอร์เป็นอาร์กิวเมนต์สตริง

นี่คือตัวอย่างวิธีการใช้สตรีมสตริง

ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;

dec: 15 hex: fผลที่ได้คือ

istringstream มีการใช้งานที่เหมือนกันมากหรือน้อย

เพื่อสรุป stringstream เป็นวิธีที่สะดวกในการจัดการสตริงเช่นอุปกรณ์ I / O ที่เป็นอิสระ

FYI ความสัมพันธ์ทางมรดกระหว่างคลาสคือ:

คลาสสตรีมสตริง


19

เพื่อตอบคำถาม stringstreamโดยทั่วไปจะช่วยให้คุณปฏิบัติกับstringวัตถุเช่น a streamและใช้streamฟังก์ชันและตัวดำเนินการทั้งหมดในนั้น

ฉันเห็นว่ามันใช้สำหรับเอาต์พุตที่จัดรูปแบบ / อินพุตที่ดีเป็นหลัก

ตัวอย่างที่ดีอย่างหนึ่งคือc++การใช้การแปลงตัวเลขเป็นวัตถุสตรีม

ตัวอย่างที่เป็นไปได้:

template <class T>
string num2str(const T& num, unsigned int prec = 12) {
    string ret;
    stringstream ss;
    ios_base::fmtflags ff = ss.flags();
    ff |= ios_base::floatfield;
    ff |= ios_base::fixed;
    ss.flags(ff);
    ss.precision(prec);
    ss << num;
    ret = ss.str();
    return ret;
};

อาจจะซับซ้อนหน่อย แต่ค่อนข้างซับซ้อน คุณสามารถสร้างstringstreamวัตถุssแก้ไขธงของใส่ตัวเลขลงด้วยและดึงมันผ่านoperator<< str()ฉันเดาว่าน่าoperator>>จะใช้ได้

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

หมายเหตุ: ฉันอาจขโมยมาจากใครบางคนใน SO และได้รับการขัดเกลา แต่ฉันไม่มีผู้เขียนต้นฉบับระบุไว้


3
หมายเหตุ: การใช้งานretไม่จำเป็นสามารถเขียนreturn ss.str();ได้
Matthieu M.

@MatthieuM. ฉันคิดว่าฉันไม่แน่ใจว่า RVO จะเตะเข้าถ้ามันเขียนแบบนั้นหรือถ้าวัตถุที่ส่งคืนโดย ss.str () จะรอดจากจุดออก วิธีนี้ทำให้ฉันรู้ว่ากำลังทำสำเนาและ RVO ก็ใช้ได้ แต่คุณคิดถูกที่สุด
luk32

จริงๆแล้ว RVO มี 2 รูปแบบ: URVO (สำหรับไม่มีชื่อนั่นคือชั่วคราว) และ NRVO (สำหรับตั้งชื่อ); คอมไพเลอร์ส่วนใหญ่ใช้ RVO แต่บางตัว จำกัด ให้ใช้เฉพาะ URVO เท่านั้น (ขึ้นอยู่กับตัวเลือกการสร้าง) โดยทั่วไปแล้วมีปัจจัยอื่น ๆ อีกมากมายที่ต้องคำนึงถึงดังนั้นคุณควรเขียนโค้ดที่สะอาดที่สุดเท่าที่จะเป็นไปได้และไม่ต้องกังวลมากเกินไปว่า RVO จะเข้ามาหรือไม่
Matthieu M.

NRVO เป็นเรื่องปกติ (เช่นเดียวกับ URVO) แต่ไม่ใช่ปัญหาเนื่องจากการย้ายตัวสร้าง
Rapptz

18

จากC ++ Primer :

istringstreamประเภทอ่านสตริง , ostringstreamเขียนสตริงและstringstreamอ่านและเขียนสตริง

ฉันเจอบางกรณีที่ทั้งสะดวกและรัดกุมในการใช้สตริงสตรี

กรณีที่ 1

เป็นหนึ่งในวิธีแก้ปัญหาสำหรับปัญหา leetcodeนี้ แสดงให้เห็นถึงกรณีที่เหมาะสมอย่างยิ่งที่การใช้สตริงสตรีมมีประสิทธิภาพและรัดกุม

สมมติว่าaและbเป็นจำนวนเชิงซ้อนที่แสดงในรูปแบบสตริงเราต้องการได้ผลลัพธ์ของการคูณaและbในรูปแบบสตริง รหัสมีดังนี้:

string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;

int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of 
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;

out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';

// final result in string format
string result = out.str() 

กรณีที่ 2

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

string simplifyPath(string path) {
    string res, tmp;
    vector<string> stk;
    stringstream ss(path);
    while(getline(ss,tmp,'/')) {
        if (tmp == "" or tmp == ".") continue;
        if (tmp == ".." and !stk.empty()) stk.pop_back();
        else if (tmp != "..") stk.push_back(tmp);
    }
    for(auto str : stk) res += "/"+str;
    return res.empty() ? "/" : res; 
 }

หากไม่มีการใช้สตริงสตรีมการเขียนโค้ดที่กระชับเช่นนี้จะเป็นเรื่องยาก


2

คุณป้อนตัวเลขและตัวอักษรและ int mystrว่างคั่นใน

จากนั้นคุณพยายามแปลงโทเค็นแรก (คั่นว่าง) เป็นintไฟล์.

โทเค็นแรกคือ RS ซึ่งไม่สามารถแปลงintเป็นศูนย์ได้ทำให้ราคาของฉันเป็นศูนย์และเราทุกคนรู้ว่าสิ่งใดให้ผลตอบแทนเป็นศูนย์

เมื่อคุณป้อนค่า int เพียงครั้งที่สองทุกอย่างจะเป็นไปตามที่คุณคาดไว้

มันเป็น RS ปลอมที่ทำให้รหัสของคุณล้มเหลว

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