Câu hỏi Chính xác thì stringstream làm gì?


Tôi đang cố gắng tìm hiểu C ++ kể 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: Lệnh bí ẩn chính xác làm gì? Trích dẫn từ tài liệu:

"Trong ví dụ này, chúng tôi thu được các giá trị số từ đầu vào tiêu chuẩn   gián tiếp. Thay vì trích xuất các giá trị số trực tiếp từ   đầu vào tiêu chuẩn, chúng tôi nhận được các dòng từ đầu vào chuẩn (cin) vào   string object (mystr), và sau đó chúng tôi trích xuất các giá trị số nguyên 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 không thể thiếu của một chuỗi và sử dụng nó làm đầu vào.

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


76
2017-12-15 12:31


gốc


Ví dụ này khá kỳ lạ, tôi chưa từng thấy stringstream sử dụng theo cách đó. Tôi thường tải các dòng, chuyển đổi nó và sau đó trích xuất bởi các bộ phận, tuy nhiên điều này rõ ràng là có ít lợi thế ở đây bởi vì cin  Là một luồng đầu vào đã ... Vì vậy, cin >> price >> quantity; sẽ đơn giản hơn rất nhiều. Đó sẽ là một lý do chính đáng KHÔNG PHẢI để sử dụng các hướng dẫn cplusplus.com. - Bartek Banachewicz
Buồn cười rằng hướng dẫn đó là lần đầu tiên tôi tiếp xúc với C ++. Trong tầm nhìn, nó khá nghèo và không đầy đủ. Tôi muốn đề nghị cuốn sách hay thay thế. - jrok
@BartekBanachewicz Có lẽ họ chỉ cần đưa ra ví dụ để chỉ ra cách stringstream công trinh. Nó là một trong những kỳ lạ có lẽ ngay cả một xấu =) Nhưng nó cho thấy bạn có thể coi chuỗi như một dòng. - luk32
Nếu nó không phải là một giới thiệu để sử dụng tiên tiến hơn của stringstream thì đó chắc chắn là một ví dụ sai. Và ngay cả khi nó là sau đó nó nên được viết khác nhau. - j_kubik
@trojansdestroy Bạn không thể hiểu được chuỗi ký tự mà không hiểu tất cả các nguyên thủy dựa trên nó, vì vậy tôi không thấy cách đọc một hướng dẫn giúp trong vấn đề đó. - Bartek Banachewicz


Các câu trả lời:


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

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

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

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

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

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

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

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

istringstream có nhiều hoặc ít hơn mức sử dụng tương tự.

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

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

string stream classes


120
2017-12-15 13:28





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

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

Một ví dụ tốt sẽ là c++ thực hiện chuyển đổi số sang đối tượng luồ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ó lẽ nó hơi phức tạp nhưng nó khá phức tạp. Bạn tạo stringstream vật ss, sửa đổi cờ của nó, đặt một số vào nó với operator<<và trích xuất thông qua str(). Tôi đoán vậy operator>> có thể được sử dụng.

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

Lưu ý: Tôi có thể đã đánh cắp nó từ một người nào đó trên SO và tinh tế, nhưng tôi không có tác giả ban đầu được ghi nhận.


15
2017-12-15 12:47



Lưu ý: việc sử dụng ret là 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 chắn nếu RVO sẽ kick-in nếu nó được viết như thế, hoặc nếu đối tượng trở về bởi ss.str () sẽ tồn tại điểm xuất cảnh. Bằng cách này tôi biết tôi đang tạo một bản sao và RVO sẽ hoạt động. Nhưng bạn có lẽ là đúng. - luk32
Trên thực tế, có 2 dạng RVO: URVO (đối với tên không xác định, đó là thời gian) và NRVO (có 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ỉ với URVO (tùy thuộc vào các tùy chọn xây dựng). Nói chung, mặc dù, có rất nhiều yếu tố khác để đưa vào tài khoản, vì vậy bạn chỉ nê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ẽ đá vào. - Matthieu M.
NRVO là phổ biến (như là URVO) tuy nhiên nó không phải là một vấn đề do di chuyển các nhà xây dựng. - Rapptz


Từ C ++ Primer:

Các istringstream loại đọc chuỗi, ostringstream viết một chuỗistringstream đọc và viết chuỗi.

Tôi đi qua một số trường hợp mà nó là cả hai thuận tiện và súc tích để sử dụng stringstream.

trường hợp 1

Nó 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 sử dụng stringstream hiệu quả và súc tích.

Giả sử a và b là những con số phức tạp được thể hiện dưới định dạng chuỗi, chúng tôi muốn có được kết quả của phép nhân a và b cũ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

Nó cũng từ một vấn đề mã vạch yêu cầu bạn đơn giản hóa chuỗi đường dẫn đã cho, một trong các giải pháp sử dụng stringstream là thanh lịch nhất mà tôi đã 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.


12
2018-06-27 14:22





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

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

Mã thông báo đầu tiên là RS không chuyển thành int, để lại một số không cho giá của tôi, và tất cả chúng ta đều biết những gì không lần bất cứ điều gì sản lượng.

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

Đó là RS giả mạo khiến mã của bạn thất bại.


2
2017-08-11 02:09