Tách xâu bằng stringstream

#include<iostream>
#include<map>
#include<string>
#include<sstream>

using namespace std;

int main()
{
	string S;
		cin >> S;
	stringstream ss(S);
	
	map<string, int> m;
	string token;
	string a[100];
	int count=0;
	while (ss >> token)
		{ 
	  		a[count] = token;
	  		count++;
		}
	for(int i=0; i<=count; i++)
		{
			cout<<a[i]<<" ";
		}
}

em mới tìm hiểu cái này, các bác giải thích giúp em sao không in được thành chuỗi với ạ??

stringstream hoạt động như một iostream (cincout).
Khi bạn nhập 1 chuỗi bằng toán tử >> thì xử lý sẽ tự động lấy chuỗi không chứa các kí khoảng trắng (khoảng cách, tab, xuống dòng). Như thế, khi dùng ss >> token thì nó đã tự tách từng từ ra cho bạn luôn, chỉ việc lưu mỗi từ nhận được vào mảng a.

Nhưng đoạn mã trên không hoạt động đâu. Vì chuỗi S không bao giờ chứa khoảng trắng. Nó cũng nhập bằng toán tử >> mà. Đúng ra, dòng cin >> S; phải là getline(cin, S);.
Đoạn mã đúng:

3 Likes

em cảm ơn bác <3
Sẵn tiện bác giúp em đoạn code này với:

#include<iostream>
#include<map>
#include<string>
#include<sstream>

using namespace std;

int main()
{
	string S;
		getline(cin, S);
	stringstream ss(S);
	
	map<string, int> m;
	string token;
	string a[100];
	int count=0;
	while (ss >> token)
		{ 
	  		a[count] = token;
	  		count++;
		}
	
	for(int i=0; i<=count; i++)
		{
			if(m.find(a[i]) == m.end())
				{
					m.insert( pair<string, int>(a[i], 1) );
				}
			else
				{
					m[a[i]]++;
				}
		}
	
	for(map<string, int>::iterator i=m.begin(); i!=m.end(); i++)
		{
			cout<< i->first <<": " << i->second << endl;
		}

}

vd:
input: abc def ghi
out put:

: 1
abc: 1
def: 1
ghi: 1

làm sao để bỏ cái " : 1" được ạ:((

à e nghĩ ra cách:

if(i!=m.begin())
{
	cout<< i->first <<": " << i->second << endl;
}

không biết có cách nào tốt hơn không ạ???

Đừng sử dụng mấy thứ vớ vẩn như vầy nữa là tự nhiên hết lỗi à bạn. Hãy sử dụng std::vector ấy.

4 Likes

i <= count là sao đây?

4 Likes

dạ, tại e đang dùng quen cái này, bác có link nào đọc về vector không ạ, e cảm ơn :kissing_heart:*

cái count này là để e đếm số phần tử trong mảng a đó bác

Không hỏi biến count đâu. Hỏi cái dấu = thôi.

3 Likes
#include<iostream>
#include<map>
#include<string>
#include<sstream>
#include<vector>

using namespace std;

int main()
{
	string S;
		getline(cin, S);
	stringstream ss(S);
	
	map<string, int> m;
	string token;
	vector<string> a;
	
	while (ss >> token)
		{ 
	  		a.push_back(token);
		}
	
	for(int i=0; i<a.size(); i++)
		{
			if(m.find(a[i]) == m.end())
				{
					m.insert( pair<string, int>(a[i], 1) );
				}
			else
				{
					m[a[i]]++;
				}
		}
	
	for(map<string, int>::iterator i=m.begin(); i!=m.end(); i++)
		{
					cout<< i->first <<": " << i->second << endl;
		}
}

e sử dụng vector cho bài này nhé các bác, có gì góp ý giúp e với, e cảm ơn :kissing_smiling_eyes:

2 Likes

Góp ý đầu tiên là đặt tên biến, độ dài tên tỉ lệ thuận với khoảng cách từ lúc khai báo tới lúc dùng lần cuối, tỉ lệ chắc cỡ 3~5 dòng/1 ký tự là hợp lý.
Thứ hai là, tại sao S in hoa mà m, a lại in thường?
Thứ ba, cái quan trọng nhất, bây giờ người ta dùng for như vầy, chứ không có xài index hay iterator nữa đâu bạn ơi (chính là cái kiểu này mới hết mấy lỗi như i <= count á):

for(auto n: a){
    m[n]++; // Chỗ này không cần check tồn tại làm gì, vì operator[] của map tự động thêm giá trị default là 0 với kiểu int nếu key không tồn tại
}

for (const auto& kv: m){
    cout << kv.first << ": " << kv.second << '\n';
}
4 Likes

C++11 mới có foreach và auto bạn :slight_smile: nên giáo trình ko bao h có.

3 Likes

Đừng nói thế chứ, /me lại rage bây giờ à. Thời buổi này nếu compiler nào không support full C++14 thì nên vứt đi mà thôi =]]

thứ nhất là bỏ code vô giữa 3 dấu ``` chứ ko phải 3 dấu *** nha :V

thứ hai là std::map<KeyType, ValueType> trong C++ có khởi tạo sẵn giá trị của m[key] là giá trị mặc định của ValueType, ở đây ValueTypeint nên nó mặc định là 0, em ko cần ktra if(m.find(a[i]) == m.end()) làm gì đâu. Viết lại thế này là được:

for(int i=0; i<a.size(); i++)
    m[a[i]]++;

thứ ba là nếu xài C++11/C++17 thì còn ngắn và đẹp hơn nữa:

// C++11
for (auto& s : a)
    m[s]++;

vòng for ở dưới nếu xài C++11 thì ngắn hơn tí:

// C++11
for (auto it = begin(m); it != end(m); it++)
     cout << it->first << ": " << it->second << endl;

nhưng viết thế này thì ngắn và đẹp hơn:

// C++11 
for (auto& kv : m)
     cout << kv.first << ": " << kv.second << endl;

nếu xài C++17 thì ngắn và đẹp hơn nhiều:

// C++17
for (auto& [key, value] : m)
     cout << key << ": " << value << endl;

em viết for (int i = 0; ...) nhiều chán rồi thì xài for (... : ...) cho quen =] Ngôn ngữ nào cũng có vòng lặp kiểu này, gọi là for-in for-each :V :V , ko chỉ C++11 mới có đâu.

5 Likes

4.0 rồi xài C++ hiện đại là đúng rồi =]

4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?