스택과 계산기

StringBuffer 클래스

5.2.2) StringBuffer 클래스

StringBuffer 클래스는 문자열을 다루기 쉽도록 필자가 고안한 클래스다. StringBuffer 클래스의 인스턴스는 다음의 행위를 수행할 수 있다.

- init: 버퍼를 인자로 받은 문자열로 초기화한다

- getc: 버퍼로부터 문자를 하나 가져온다

- ungetc: 버퍼에서 읽었던 값을 되돌린다

- add: 버퍼의 끝에 문자 또는 문자열을 추가한다

- is_empty: 버퍼가 비어있는지 확인한다

다음은 StringBuffer 클래스를 구현한 것이다.

StringBuffer.h

#ifndef __HANDY_STRINGBUFFER_H__

#define __HANDY_STRINGBUFFER_H__

 

#include <string>

class StringBuffer {

std::string str;

unsigned len;

unsigned idx;

 

public:

StringBuffer(const char *s = "");

StringBuffer(const std::string &str);

~StringBuffer();

 

// 버퍼를 문자열로 초기화합니다.

void init(const char *str);

void init(const std::string &str);

 

// 버퍼로부터 문자를 하나 읽습니다포인터가 이동합니다.

char getc();

// 버퍼의 포인터가 가리키는 문자를 가져옵니다포인터는 이동하지 않습니다.

char peekc() const;

// 버퍼에서 읽었던 값을 되돌립니다되돌릴 수 없으면 false를 반환합니다.

bool ungetc();

 

// 버퍼의 끝에 문자 또는 문자열을 추가합니다.

void add(char c);

void add(const char *s);

void add(const std::string &str);

 

// 버퍼가 비어있다면 true, 값을 더 읽을 수 있다면 false를 반환합니다.

bool is_empty() const;

};

 

#endif

StringBuffer.cpp

#include "StringBuffer.h"

#include <string>

typedef std::string Exception;

StringBuffer::StringBuffer(const char *s) : str(s), idx(0) { this->len = this->str.length(); }

StringBuffer::StringBuffer(const std::string &str) : str(str), idx(0) { this->len = this->str.length(); }

StringBuffer::~StringBuffer() {}

void StringBuffer::init(const char *str) {

this->str = str;

this->idx = 0;

this->len = this->str.length();

}

void StringBuffer::init(const std::string &str) {

this->str = str;

this->idx = 0;

this->len = this->str.length();

}

char StringBuffer::getc() {

if (idx >= len) {

throw Exception("Buffer is empty");

}

return str[idx++];

}

char StringBuffer::peekc() const {

if (idx >= len) {

throw Exception("Buffer is empty");

}

return str[idx];

}

bool StringBuffer::ungetc() {

if (idx > 0) {

--idx;

return true;

}

else {

return false;

}

}

void StringBuffer::add(char c) {

this->str += c;

}

void StringBuffer::add(const char *s) {

this->str += s;

}

void StringBuffer::add(const std::string &str) {

this->str += str;

}

bool StringBuffer::is_empty() const {

return (idx >= len);

}

다음은 StringBuffer 클래스를 사용하는 예제이다.

13_StringBufferMain.cpp

#include <iostream>

#include "StringBuffer.h"

typedef std::string Exception;

int main(void) {

try {

StringBuffer buffer;

buffer.init("Hello, world!");

while (buffer.is_empty() == false) {

std::cout << buffer.getc() << std::endl;

}

return 0;

}

catch (Exception &ex) {

std::cerr << ex.c_str() << std::endl;

return 1;

}

}

그리고 이를 이용하여 사칙 연산 계산기를 다시 작성할 수 있다.

14_basic4_StringBuffer.cpp

int ascii_to_int(StringBuffer &buffer) { // 문자열을 정수로 변환하고 그 값을 반환

int digit = 0;

int value = 0;

char ch;

while (buffer.is_empty() == false) {

if (is_digit(ch = buffer.getc()) == false) {

buffer.ungetc(); // 아직 읽지 않은 값이므로 되돌린 후 탈출한다

break;

}

digit = ch - '0';

value = 10 * value + digit;

}

return value;

}

int calculate(const char *expr) { // 넘겨받은 식을 계산하여 값을 반환한다

StringBuffer buffer(expr);

if (is_digit(buffer.peekc()) == false) { // 입력의 처음이 숫자가 아니라면 예외

throw Exception("타당하지 않은 입력입니다.");

}

int left = ascii_to_int(buffer); // 왼쪽에 나타나는 수 획득

if (buffer.is_empty()) { // 입력이 끝났다면 획득한 정수를 반환하고 종료

return left;

}

// 연산자 획득사칙 연산에 대해서만 다루므로 연산자 길이는 반드시 1

char op = buffer.getc(); // 문자열 포인터가 가리키는 연산자를 획득 후 포인터 이동

int right = ascii_to_int(buffer); // 오른쪽에 나타나는 수 획득

if (buffer.is_empty() == false) { // 입력이 아직 끝나지 않았다면 예외 발생

throw Exception("두 개의 피연산자로만 연산할 수 있습니다.");

}

// 획득한 값과 연산자를 이용하여 연산

int retVal = 0;

switch (op) {

case '+': retVal = left + right; break;

case '-': retVal = left - right; break;

case '*': retVal = left * right; break;

case '/': retVal = left / right; break;

default: throw Exception("올바른 연산자가 아닙니다.");

}

return retVal;

}

독자 중엔 StringBuffer 클래스가 이전과 크게 편의성에서 차이가 나지 않는다고 생각하는 사람도 있을 것이다그 경우에는 자신이 원하는 방법으로 진행하면 된다사실 StringBuffer 클래스는 완성된 클래스가 아니고프로젝트를 진행하면서 기능을 추가하여이 클래스가 없이 작업하는 것을 상상할 수 없을 정도로 만들 것이다이와 같이StringBuffer 클래스를 활용하고 이해할 수 있었다.

 

댓글

댓글 본문