IT 프로그래밍/자료구조

[자료구조] c++ 주소록 프로그램

기술1 2024. 9. 21. 17:56
반응형

C++의 단어 쪼개기

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

int main()
{
	string line;
	while (getline(cin, line)) {
		cout << line << ":" << line.length() << endl;
		vector<string> tokens = split_line(line, ' ');
		for (string str : tokens)
			cout << str << endl;
	}
	return 0;
}

vector<string> split_line(string& line, char delimiter) {
	vector<string> tokens;
	stringstream sstream(line);
	string str;
	while (getline(sstream, str, delimiter))
		tokens.push_back(str);
	return tokens;
}

string vector를 만들어서 저장을 한 다음에 vector 자체를 return 해주는 것이 간명한 인터페이스라고 볼 수 있습니다 .이렇게 동작하도록 만들어진 함수입니다.

 

tokens를 저장할 벡터 즉 split_line을 선언하고 stringstream을 사용함으로써 stringstream sstream(line)을 하면 일렬로 나열된 line을 읽으며 getline(sstream, str, delimiter)를 하면 string_stream으로부터 delimiter가 나올때까지 읽어줍니다. 

 

C의 단어 쪼개기

int main()
{
	char cstr[] = " hello world! ";
	string str = "   hello   world!   ";

	char* t = strtok(cstr, " ");
	for (int i = 0; t != NULL; i++) {
		printf("%d:%s\n", i, t);
		t = strtok(NULL, " ");
	}

	cout << endl;
	vector<string> tokens = split_line(str, ' ');
	for (int i = 0; i < tokens.size(); i++) {
		cout << i << ":" << tokens[i] << endl;
	}
}

vector<string> split_line(string& line, char delimiter) {
	vector<string> tokens;
	stringstream sstream(line);
	string str;
	while (getline(sstream, str, delimiter))
		tokens.push_back(str);
	return tokens;
}

 

 

C++단어 쪼개기

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cctype>
#include <cassert>
#include <vector>
using namespace std;

struct Person {
	string name, address;
	string phone, email, web;
};

vector<Person> directory;

vector<string> split_line(string& line, char delimiter) {
	vector<string> tokens;
	stringstream sstream(line);
	string str;
	while (getline(sstream, str, delimiter))
		tokens.push_back(str);
	return tokens;
}

string trim(string str) {
	int s = 0, t = str.length() - 1;
	while (s < str.length() && isspace(str[s]))
		s++;
	while (t >= 0 && isspace(str[t]))
		t--;
	if (s <= t) 
		return str.substr(s, t - s + 1);
	else
		return "";
}

substr(pos, len)은 string에서 위치 pos에서 시작하여 길이가 len인 substring을 생성하는 것입니다. 그 문자열을 return해주는 것입니다. 그러면 trim이 완료가 된 것입니다. 

 

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cctype>
#include <cassert>
#include <vector>
using namespace std;

struct Person {
	string name, address;
	string phone, email, web;
};

vector<Person> directory;

vector<string> split_line(string& line, char delimiter) {
	vector<string> tokens;
	stringstream sstream(line);
	string str;
	while (getline(sstream, str, delimiter))
		tokens.push_back(str);
	return tokens;
}

string trim(string str) {
	int s = 0, t = str.length() - 1;
	while (s < str.length() && isspace(str[s]))
		s++;
	while (t >= 0 && isspace(str[t]))
		t--;
	if (s <= t) 
		return str.substr(s, t - s + 1);
	else
		return "";
}

void load_data(string file_name) {
	string line;

	ifstream infile(file_name);

	while (getline(infile, line)) {
		vector<string> tokens = split_line(line, '\t');

		assert(tokens.size() >= 4 && tokens.size() <= 5);

		Person p;
		p.name = tokens.at(0);
		p.address = tokens.at(1);
		p.phone = tokens.at(2);
		p.email = tokens.at(3);
		if (tokens.size() == 5)
			p.web = tokens.at(4);

		directory.push_back(p);
	}
	infile.close();
}

void print_person(Person& p) {
	cout << p.name << ":" << endl;
	cout << "    Address: " << p.address << ":" << endl;
	cout << "    Phone: " << p.phone << ":" << endl;
	cout << "    Email: " << p.email << ":" << endl;
	cout << "    Web: " << p.web << ":" << endl;
}

void list_directory() {
	for (auto& person : directory) {
		print_person(person);
	}
}

void search_directory(string& prefix) {
	for (auto& p : directory) {
		if (p.name.compare(0, prefix.size(), prefix) == 0)
			print_person(p);
		else if (p.name.compare(0, prefix.size(), prefix) > 0)
			break;
	}
}

Person get_person_info(string name) {
	Person p;
	string line;
	p.name = name;
	cout << "   Address: ";
	getline(cin, line);
	p.address = trim(line);
	cout << "   Phone: ";
	getline(cin, line);
	p.phone = trim(line);
	cout << " Email: ";
	getline(cin, line);
	p.email = trim(line);
	cout << " Web ";
	getline(cin, line);
	p.web = trim(line);

	return p;
}

void add_person(string name) {
	Person p = get_person_info(name);
	auto it = directory.begin();
	while (it != directory.end() && it->name <= name)
		it++;
	it = directory.insert(it, p);
}

void delete_person(string name) {
	string answer;
	for (auto it = directory.begin(); it != directory.end(); ) {
		if (it->name.compare(0, name.size(), name) == 0) {
			cout << "Want to delete '" << it->name << "'?";
			cin >> answer;
			if (answer == "yes" || answer == "y")
				it = directory.erase(it);
			else
				it++;
		}
		else if (it->name.compare(0, name.size(), name) > 0)
			break;
		else
			it++;
	}
}

void save_directory() {
	ofstream outfile("address.tsv");
	for (auto& p : directory)
		outfile << p.name << '\t' << p.address << '\t' << p.phone
		<< '\t' << p.email << '\t' << p.web << endl;
	outfile.close();
}

int main() {
	load_data("address.tsv");
	string command, arguments;
	while (1) {
		cout << "$ ";
		cin >> command;
		if (command == "exit")
			break;
		if (command == "list")
			list_directory();
		else if (command == "find") {
			getline(cin, arguments);
			string name = trim(arguments);
			if (name.length() <= 0)
				continue;
			search_directory(name);
		}
		else if (command == "add") {
			getline(cin, arguments);
			string name = trim(arguments);
			if (name.length() <= 0)
				continue;
			add_person(name);
		}
		else if (command == "delete") {
			getline(cin, arguments);
			string name = trim(arguments);
			if (name.length() <= 0)
				continue;
			delete_person(name);
		}
		else if (command == "save") {
			save_directory();
		}
	}
	return 0;
}

이렇게 c++ string은 c의 문자열보다 다루기 쉬우며 vector는 배열보다 편리합니다. 특히 참조변수는 프로그램의 성능에 도움이 되는데요. 주소 정보 중에 만약 누락된 항목이 있으면 split_line은 empty string을 생성해주기 때문에 이러한 문제도 없습니다. 

반응형