Chính xác thì stringstream làm gì?


107

Tôi đang cố gắng học C ++ từ hôm qua và tôi đang sử dụng tài liệu này: http://www.cplusplus.com/files/tutorial.pdf (trang 32). Tôi đã tìm thấy một mã trong tài liệu và tôi đã chạy nó. Tôi đã thử nhập 5,5 Rs cho giá và một số nguyên cho số lượng và đầu ra là 0. Tôi đã thử nhập 5,5 và 6 và đầu ra là chính xác.

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

Câu hỏi: Chính xác thì lệnh mystring làm gì? Trích dẫn từ tài liệu:

"Trong ví dụ này, chúng tôi nhận các giá trị số từ đầu vào chuẩn một cách gián tiếp. Thay vì trích xuất các giá trị số trực tiếp từ đầu vào chuẩn, chúng tôi lấy các dòng từ đầu vào chuẩn (cin) thành một đối tượng chuỗi (mystr) và sau đó chúng tôi trích xuất số nguyên các giá trị từ chuỗi này thành một biến kiểu int (số lượng). "

Ấn tượng của tôi là hàm sẽ lấy phần tích hợp của một chuỗi và sử dụng nó làm đầu vào.

(Tôi không biết làm thế nào để đặt một câu hỏi ở đây. Tôi cũng mới học lập trình) Cảm ơn bạn.


18
Ví dụ này hơi kỳ lạ, tôi chưa bao giờ thấy stringstreamđược sử dụng theo cách đó. Tôi thường tải dòng, chuyển đổi nó và sau đó trích xuất theo từng phần, tuy nhiên điều này rõ ràng có ít lợi thế ở đây vì đã cin một dòng đầu vào rồi ... Vì vậy, cin >> price >> quantity;sẽ đơn giản hơn nhiều. Đó sẽ là một lý do chính đáng để KHÔNG sử dụng các hướng dẫn của cplusplus.com.
Bartek Banachewicz

6
Thật buồn cười khi hướng dẫn đó là lần đầu tiên tôi tiếp xúc với C ++. Trong nhận thức muộn màng, nó khá nghèo nàn và không đầy đủ. Thay vào đó, tôi muốn đề xuất một cuốn sách hay .
jrok

@BartekBanachewicz Có thể họ chỉ cần đưa ra ví dụ để hiển thị cách stringstreamhoạt động. Nó là một điều kỳ lạ thậm chí có thể là một điều tồi tệ =) Nhưng nó cho thấy bạn có thể coi chuỗi như một luồng.
luk32

Nếu nó không phải là phần giới thiệu về các cách sử dụng nâng cao hơn stringstreamthì chắc chắn đó là một ví dụ sai. Và ngay cả khi nó là như vậy thì nó nên được viết khác đi.
j_kubik

1
@trojansdestroy Bạn không thể hiểu stringstream nếu không hiểu tất cả các nguyên thủy mà nó dựa trên, vì vậy tôi không thấy việc đọc hướng dẫn sẽ giúp ích như thế nào về vấn đề đó.
Bartek Banachewicz

Câu trả lời:


163

Đôi khi rất thuận tiện khi sử dụng stringstream để chuyển đổi giữa các chuỗi và các kiểu số khác. Cách sử dụng của stringstreamtương tự như cách sử dụng của iostream, vì vậy nó không phải là một gánh nặng để học.

Chuỗi chuỗi có thể được sử dụng để vừa đọc chuỗi vừa ghi dữ liệu vào chuỗi. Nó chủ yếu hoạt động với bộ đệm chuỗi, nhưng không có kênh I / O thực.

Các hàm thành viên cơ bản của lớp stringstream là

  • str(), trả về nội dung của bộ đệm của nó ở kiểu chuỗi.

  • str(string), đặt nội dung của bộ đệm thành đối số chuỗi.

Đây là một ví dụ về cách sử dụng các luồng chuỗi.

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

Kết quả là dec: 15 hex: f.

istringstream ít nhiều đều có cùng cách sử dụng.

Tóm lại, stringstream là một cách thuận tiện để thao tác các chuỗi giống như một thiết bị I / O độc lập .

FYI, mối quan hệ kế thừa giữa các lớp là:

các lớp dòng chuỗi


19

Để trả lời câu hỏi. stringstreamvề cơ bản cho phép bạn coi một stringđối tượng giống như một đối tượng stream, và sử dụng tất cả các streamhàm và toán tử trên đó.

Tôi thấy nó được sử dụng chủ yếu cho độ tốt đầu ra / đầu vào được định dạng.

Một ví dụ điển hình là c++thực hiện chuyển đổi số thành luồng đối tượng.

Ví dụ có thể:

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

Có thể nó hơi phức tạp nhưng nó khá phức tạp. Bạn tạo stringstreamđối tượng ss, sửa đổi cờ của nó, đặt một số vào nó operator<<và trích xuất nó qua str(). Tôi đoán rằng operator>>có thể được sử dụng.

Cũng trong ví dụ này, stringbộ đệm bị ẩn và không được sử dụng rõ ràng. Nhưng sẽ là quá dài cho một bài đăng để viết về mọi khía cạnh có thể có và trường hợp sử dụng.

Lưu ý: Tôi có thể đã lấy cắp nó từ một ai đó trên SO và tinh chỉnh, nhưng tôi không có ghi chú tác giả gốc.


3
Lưu ý: việc sử dụng retlà không cần thiết, người ta có thể viết return ss.str();.
Matthieu M.

@MatthieuM. Tôi nghĩ rằng tôi không chắc liệu RVO sẽ khởi động nếu nó được viết như vậy hay nếu đối tượng được trả về bởi ss.str () sẽ tồn tại ở điểm thoát. Bằng cách này, tôi biết mình đang tạo một bản sao và RVO sẽ hoạt động. Nhưng bạn có lẽ đúng nhất.
luk32

Trên thực tế, có 2 hình thức RVO: URVO (cho không tên, đó là tạm thời) và NRVO (cho tên); hầu hết các trình biên dịch thực hiện RVO, nhưng một số hạn chế nó chỉ ở URVO (tùy thuộc vào các tùy chọn xây dựng). Nói chung, tuy nhiên, có rất nhiều yếu tố khác để đưa vào tài khoản, vì vậy bạn chỉ cần viết mã sạch nhất có thể và không lo lắng quá nhiều về việc liệu RVO sẽ kick vào.
Matthieu M.

NRVO là phổ biến (cũng như URVO) tuy nhiên nó không phải là vấn đề do các hàm tạo di chuyển.
Rapptz

18

Từ C ++ Primer :

Kiểu istringstream đọc một chuỗi , ostringstream ghi một chuỗistringstream đọc và ghi chuỗi .

Tôi đã gặp một số trường hợp sử dụng stringstream vừa tiện lợi vừa ngắn gọn .

trường hợp 1

Nó là từ một trong những giải pháp cho vấn đề leetcode này . Nó thể hiện một trường hợp rất phù hợp khi việc sử dụng stringstream hiệu quả và ngắn gọn.

Giả sử ablà các số phức được biểu diễn ở định dạng chuỗi, chúng ta muốn lấy kết quả của phép nhân abcũng ở định dạng chuỗi. Mã như sau:

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

trường hợp 2

Cũng do vấn đề leetcode yêu cầu bạn đơn giản hóa chuỗi đường dẫn đã cho, một trong những giải pháp sử dụng stringstreamgiải pháp thanh lịch nhất mà tôi từng thấy:

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

Nếu không sử dụng chuỗi ký tự, sẽ rất khó để viết mã ngắn gọn như vậy.


2

Bạn đã nhập một chữ và số và int, trống được phân cách trong mystr.

Sau đó, bạn đã cố gắng chuyển đổi mã thông báo đầu tiên (được phân cách trống) thành một int.

Mã thông báo đầu tiên là RS không thể chuyển đổi thành int, để lại số 0 cho myprice và tất cả chúng ta đều biết mọi thứ mang lại lợi nhuận bằng 0 lần.

Khi bạn chỉ nhập giá trị int lần thứ hai, mọi thứ hoạt động như bạn mong đợi.

Chính RS giả đã khiến mã của bạn bị lỗi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.