[C++] istringstream is() 에서 is >> i 로 ascii 숫자를
글쓴이: gyxor / 작성시간: 일, 2004/04/25 - 12:45오전
#include<iostream> #include<sstream> using namespace std; int main(){ char data[20] = "12eee55"; char temp1[20] ={ 0}; char temp2[20] ={ 0}; short i=0; istringstream is(data); is >> i; is.getline(temp2,4); cout << i << endl; cout << temp2 << endl; is >> i; cout << i; return 0; }
is >> i 를 이용하면 ascii형태로 저장된 문자열에서 이진수를 뽑아낼 수 있습니다.
예를들어
short i = 13; 일때
is << i;를 해주게 되면 13이 이진수로 변환되어.. 케리지리턴 0d가 들어가는것이 아니라..
1과 3이 들어가게 됩니다.
반대로
is >> i;를 해주게 되면 다시 short형의 이진수로 변환됩니다.
매우 편리한 기능인데요..
중대한 문제가 생겼습니다.
위 소스의 실행결과는
12
eee
55
가 아니라
12
eee
12
입니다.
문자열뒤에 숫자값이 위치하게 되면 위 기능이 수행이 안됩니다.
예를들어
12abc일때는 12를 읽어낼수 있지만
abc12일때는 12를 읽어낼수 없습니다.
이것은 버그가 아닌가요?
설명부탁드립니다.
Forums:
istringstream 은 istream 일종인가요? 그 입력의 소스가
istringstream 은 istream 일종인가요? 그 입력의 소스가 문자열이라는 것이 특징이겠군요.
그 문자열의 숫자를 읽어오는 인터페이스는 (클래스 멤버와 오버로드 함수로) istream의 상속이면 모두 구현하고 있을 것입니다.
istringstream의 객체를 >> 연산자 함수를 오버로딩해서 어떤 숫자 타입을 얻는 것은 문자열이 미리 그렇게 준비되어야 한다고 생각합니다.
그러니까, 숫자라고 확신하는 경우에만 사용해야 한다는 것입니다. 만약 문자열이 숫자가 아니라면 당연히 정확한 값을 돌려주지 못하겠죠. 숫자로 표현하지 않은 문자열을 어떻게 내부 숫자 타입으로 바꿀 수가 있겠습니까. 그리고, 숫자를 표현하는 문자들이 아닌 경우까지를 찾아서 숫자로 바꾼다는 것을 알면 지금의 상황을 이해할 수 있을 것 같습니다.
그리고, 그 숫자표현이 10진수, 8진수, 16진수로 받을 수 있는데, 이것은 manipulator를 찾아보시면 됩니다. (이것을 조절하면 공백 무시 등도 조절할 수 있습니다.) 만약 16진수 입력모드라면 위의 abc12 같은 표현도 입력가능하겠죠. (물론 16진의 의미로...)
C++ 연산자는 피연산자의 정확한 type을 확인할 때까지 최적의 type을 찾습니다. 그런데 입력 소스의 문자열중 숫자를 표현하는 문자가 아닌데 그것을 integer형으로 받는다면 무슨 의미가 있겠습니까?
하여튼, 문자열에서 숫자와 문자를 미리 구분하지 않으면 소용없다는 것이구요. 소스 데이터의 구조가 어떤지에 따라 전략을 다르게 선택하여야 합니다.
만약 소스 데이터가 어떤 형식이 있다면 정규식으로 토큰을 구분하든가 아니면 어떤 구분자 (공백, 탭, 쉼표 등)로 구분을 한 후 이것이 숫자다 아니면 문자열이다로 해석한 후 변환해야 합니다.
한번 곰곰히 생각해보시면 어떤 경우인지 아실 수 있을 것입니다.
예를 드신 것중에 is << i 라는 표현이 가능한가요? istream은 어떤 것에서 어떤 변수에 값을 주는 것이지 그 반대는 아예 연산자가 없을텐데요?
그리고 '문자열에서 이진수를 뽑는다'는 표현때문에 아주 질문 내용을 파악하기가 어려웠습니다. 결국 문자열의 숫자 표현을 C++ 내부의 숫자 타입으로 바꿔준다는 것이라고 이해했습니다.
p.s. 1
제 개인적으로 stream 계열의 클래스들의 용법이나 친절한 설명이 제대로 없기 때문이기도 하겠지만, 사용하기 상당히 까다롭고 어떤 경우에는 번거롭고, 또 다른 경우에는 사용할 수 없는 문제도 있었습니다. 그리고, 오래전의 인터페이스가 그대로 굳혀져서 새롭게 디자인되어야 하는 부분도 있다고 봅니다만, 표준안이 바뀌지는 않겠지요. 또하나 뭐가 앞으로 지원하지 않고 (표준에서 빠지고) 들어가는지 헷갈리기도 하구요. 하여튼 좀 사용하기 꺼려지는 것중에 하나입니다.
p.s. 2
이것과 좀 반대이긴 하지만, 다음 사이트도 한번 참고하시면 좋겠습니다.
http://www.gotw.ca/publications/mill19.htm
답변감사합니다.
말씀하신대로..
istringstream 은 입력 스트림이라서 << 연산자는 없더라구요..
그래도
ostringstream 으로 하면 << "문자열" 이 가능하고
stringstream으로 하면 둘다 되더군요..
file스트림 처리 하고 거의 같은거 같습니다.
___________________________________________
#include<iostream>
#include<sstream>
using namespace std;
int main(){
short i=0;
char data[20] = "12ee\n55";
char temp1[20] ={ 0};
char temp2[20] ={ 0};
char a = 0;
stringstream os(temp1);
os << data;
os >> i;
cout << i;
os.getline(temp1,4);
cout << temp1;
os >> i;
cout << i;
return 0;
}
____________________________________________________
위소스에선 char data[20] = "12ee\n55"; getline이 최대값에 의해 종료되지않고 구분자(\n)에 의해서 종료가 되었습니다.
그리고 정상수행됩니다.
문제의 원인은 getline에 있었습니다.
getilne이 구분자에의해 종료되지 않고 최대값에의해 종료된경우
getline()의 최대값이 4라고 할때 구분자 전까지 문자열 길이가 3개를 넘으면
문자열을 3개까지만 읽히고 failbit 가 셋팅되어서 이후에 나오는 getline()은
수행이 안되는것은 알고있었는데요...
스트림에 까지 영향을 주는지 처음 알았습니다.
____________________________________________________
int main(){
short i=0;
char data[20] = "12eee55";
char temp1[20] ={ 0};
char temp2[20] ={ 0};
char a = 0;
stringstream os(temp1);
os << data;
os >> i;
cout << i;
os.getline(temp1,4);
cout << temp1;
a = os.get();
cout << a;
return 0;
}
____________________________________________________
최대값을 넘어서 종료한 경우 getline() 이 스트림에 어떠한 영향을 주는지
알아보려고 위 소스를 수행해 봤습니다.
결과는
12eee
스티림 os에 처음 12ee\n55 문자열이 들어가고 그다음 i 짧은 정
스티림 os에 처음 12ee\n55 문자열이 들어가고 그다음 i 짧은 정수에 12를 빼오고 이것을 출력하니 12가 나오구요.
그다음에 os에서 최대 4문자까지의 버퍼인 temp1에 한 라인을 읽어오는데 ee\n까지 처리되니까 temp1에 ee까지 읽히구요. 처리는 \n까지 되었겠죠. (다음번 읽기는 5부터)
그다음 get함수로 한문자를 읽어오니 5한자를 읽어오구요.
getline이 이상한 동작을 하고 있지는 않는데요...
[quote="bugiii"]스티림 os에 처음 12ee\n55 문자열이
올리다가 실수로 12ee\n55 를 12eee55로 안바꿔서
다시 수정해놨습니다. 아래쪽 파란색 부분입니다.
버퍼가 모자라는 에러라고 생각할테니까요. getline 다음에 os.fa
버퍼가 모자라는 에러라고 생각할테니까요. getline 다음에 os.fail() 같은걸로 확인하시면 되구요. 다음 진행은 os.clear()라고 하시면 정상동작을 다시 합니다.
추가로 exception을 끄고 킬 수도 있으니 정확한 리퍼런스를 한번 참고하시는 것도 도움이 될 것 같습니다.
http://www.cplusplus.com 여기정도가 좋은 출발점 같습니다.
답변감사합니다.
그렇군요~
failbit가 셋팅되면 스트림을 비우는게 아니라 함수 수행만 안되는것이었군요..
os.clear() 하니까 되는군요.. 왜 이생각을 못했는지..
좋은 사이트도 감사합니다.
is.getline(temp2, 1024, '5');is.seekg(
is.getline(temp2, 1024, '5');
is.seekg(-1, ios::cur);
이런 식으로 해줘도 되네요. getline은 delimiter까지 읽지만 delimiter를
버퍼에 포함하지는 않기 때문에 현재 stream에서 뒤로 한 칸 간 것입니다.
댓글 달기