Apa sebenarnya yang dilakukan stringstream?

107

Saya mencoba mempelajari C ++ sejak kemarin dan saya menggunakan dokumen ini: http://www.cplusplus.com/files/tutorial.pdf (halaman 32). Saya menemukan kode di dokumen dan saya menjalankannya. Saya mencoba memasukkan Rs 5,5 untuk harga dan bilangan bulat untuk kuantitas dan hasilnya adalah 0. Saya mencoba memasukkan 5,5 dan 6 dan hasilnya benar.

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

Pertanyaan: Apa sebenarnya yang dilakukan perintah mystring? Mengutip dari dokumen:

"Dalam contoh ini, kami memperoleh nilai numerik dari input standar secara tidak langsung. Alih-alih mengekstraksi nilai numerik langsung dari input standar, kami mendapatkan baris dari input standar (cin) ke dalam objek string (mystr), lalu kami mengekstrak integer nilai dari string ini menjadi variabel berjenis int (kuantitas). "

Kesan saya adalah bahwa fungsinya akan mengambil bagian integral dari string dan menggunakannya sebagai input.

(Saya tidak tahu persis bagaimana mengajukan pertanyaan di sini. Saya juga baru dalam pemrograman) Terima kasih.

jacknad
sumber
18
Contoh ini agak aneh, saya belum pernah melihat yang stringstreamdigunakan seperti itu. Saya biasanya memuat baris, mengubahnya dan kemudian mengekstraknya berdasarkan bagian, namun ini jelas memiliki sedikit keuntungan di sini karena cin sudah menjadi aliran input ... Jadi cin >> price >> quantity;akan jauh lebih sederhana. Itu akan menjadi alasan yang bagus untuk TIDAK menggunakan tutorial cplusplus.com.
Bartek Banachewicz
6
Lucu bahwa tutorial itu adalah pemaparan pertama saya ke C ++. Kalau dipikir-pikir, ini sangat buruk dan tidak lengkap. Saya akan menyarankan buku yang bagus sebagai gantinya.
jrok
@BartekBanachewicz Mungkin mereka hanya perlu memberikan contoh untuk menunjukkan cara stringstreamkerjanya. Ini aneh bahkan mungkin buruk =) Tapi ini menunjukkan Anda dapat memperlakukan string sebagai aliran.
luk32
Jika ini bukan pengantar untuk penggunaan yang lebih maju stringstreammaka itu pasti contoh yang salah. Dan bahkan jika itu maka harus ditulis berbeda.
j_kubik
1
@trojansdestroy Anda tidak dapat memahami stringstream tanpa memahami semua primitif yang mendasarinya, jadi saya tidak melihat bagaimana membaca tutorial membantu dalam hal itu.
Bartek Banachewicz

Jawaban:

163

Terkadang sangat mudah menggunakan stringstream untuk mengonversi antara string dan tipe numerik lainnya. Penggunaannya stringstreammirip dengan penggunaan iostream, sehingga tidak menjadi beban untuk belajar.

Stringstream dapat digunakan untuk membaca string dan menulis data ke dalam string. Ini terutama berfungsi dengan buffer string, tetapi tanpa saluran I / O nyata.

Fungsi anggota dasar dari kelas stringstream adalah

  • str(), yang mengembalikan konten buffernya dalam tipe string.

  • str(string), yang menyetel konten buffer ke argumen string.

Berikut adalah contoh cara menggunakan aliran string.

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

Hasilnya adalah dec: 15 hex: f.

istringstream kurang lebih penggunaannya sama.

Singkatnya, stringstream adalah cara mudah untuk memanipulasi string seperti perangkat I / O independen .

FYI, hubungan pewarisan antar kelas adalah:

kelas aliran string

richard.g
sumber
19

Untuk menjawab pertanyaan itu. stringstreampada dasarnya memungkinkan Anda untuk memperlakukan stringobjek seperti stream, dan menggunakan semua streamfungsi dan operator di atasnya.

Saya melihatnya digunakan terutama untuk kebaikan output / input yang diformat.

Salah satu contoh yang baik adalah c++implementasi konversi angka menjadi objek aliran.

Contoh yang memungkinkan:

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

Mungkin agak rumit tapi cukup rumit. Anda membuat stringstreamobjek ss, memodifikasi benderanya, memasukkan nomor ke dalamnya operator<<, dan mengekstraknya melalui str(). Saya rasa itu operator>>bisa digunakan.

Juga dalam contoh ini stringbuffer disembunyikan dan tidak digunakan secara eksplisit. Tapi itu akan menjadi posting yang terlalu panjang untuk ditulis tentang setiap aspek yang mungkin dan kasus penggunaan.

Catatan: Saya mungkin mencurinya dari seseorang di SO dan disempurnakan, tetapi saya tidak memiliki catatan penulis asli.

luk32
sumber
3
Catatan: penggunaan rettidak perlu, seseorang bisa menulis return ss.str();.
Matthieu M.
@Bayu_joo Saya pikir saya tidak yakin apakah RVO akan menendang jika ditulis seperti itu, atau jika objek yang dikembalikan oleh ss.str () akan bertahan dari titik keluar. Dengan cara ini saya tahu saya sedang membuat salinannya, dan RVO akan berfungsi. Tapi kemungkinan besar Anda benar.
luk32
Sebenarnya ada 2 bentuk RVO: URVO (untuk yang tidak disebutkan namanya, yaitu sementara) dan NRVO (untuk diberi nama); kebanyakan kompiler mengimplementasikan RVO, tetapi beberapa membatasinya hanya untuk URVO (bergantung pada opsi build). Secara umum, ada banyak faktor lain yang harus dipertimbangkan, jadi Anda sebaiknya menulis kode yang paling bersih dan tidak terlalu khawatir tentang apakah RVO akan berlaku.
Matthieu M.
NRVO adalah umum (seperti URVO) namun itu bukan masalah karena konstruktor bergerak.
Rapptz
18

Dari C ++ Primer :

The istringstream jenis membaca string yang , ostringstream menulis tali , dan stringstream membaca dan menulis string yang .

Saya menemukan beberapa kasus di mana nyaman dan ringkas untuk menggunakan stringstream .

kasus 1

Ini dari salah satu solusi untuk masalah leetcode ini . Ini mendemonstrasikan kasus yang sangat cocok dimana penggunaan stringstream efisien dan ringkas.

Misalkan adan bmerupakan bilangan kompleks yang diekspresikan dalam format string, kita ingin mendapatkan hasil perkalian adan bjuga dalam format string. Kodenya adalah sebagai berikut:

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

kasus 2

Ini juga dari masalah leetcode yang mengharuskan Anda untuk menyederhanakan string jalur yang diberikan, salah satu solusi menggunakan stringstream adalah yang paling elegan yang pernah saya lihat:

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

Tanpa penggunaan stringstream, akan sulit untuk menulis kode yang begitu ringkas.

jdhao
sumber
2

Anda memasukkan alfanumerik dan int, dipisahkan dengan kosong mystr.

Anda kemudian mencoba mengonversi token pertama (dibatasi kosong) menjadi int.

Token pertama adalah RS yang gagal untuk dikonversi int, menyisakan nol untuk myprice, dan kita semua tahu berapa hasil nol dikalikan.

Saat Anda hanya memasukkan nilai int untuk kedua kalinya, semuanya bekerja seperti yang Anda harapkan.

Itu RS palsu yang menyebabkan kode Anda gagal.

ilocos joe
sumber