[질문] 임의의 문자열을 토큰으로 잘라내는 효율적인 방법

sabihanl의 이미지

임의의 문자열이 아래와 같이 있고,
string Question = "test|test2|sub_len|sub11$sub12$sub13|sub21$sub22$sub23|sub31$sub32$sub33|";
char *tempP에도 Question의 주소를 넣어놨습니다.(printf("[%s]",tempP)하면 위와 같은 문자열이 찍힙니다.)

토큰은 |,$,^입니다. test와 test2는 임의의 데이터 이고,
sub_len은 뒤에 나올 sub test($를 구분자로 갖는)의 갯수 입니다.
토큰 ^는 sub11,sub12,sub13내부에서 다시 토큰으로 이용됩니다.(복잡해라 ㅠ _ㅠ)

위와 같은 문자열을 먼저 |로 잘라내고 sub_len을 얻은 다음
sub_len을 이용하여 포문등을 돌려서 다시 $를 이용하여 안의 내용을 얻어내야 하는 상황인데
sub11,sub12,sub13등의 sub string에는 |,$,^등의 문자가 올수 있습니다.(모든 문자가 sub string으로 가능합니다.)
따라서 sub11안에 있는 |와 $는 토큰과 구분되어지기위하여 ^|, ^$, ^^으로 변형되어 저장 됩니다.

최종적으로 얻어내야할 내용은 벡터로 구성되어야 하기 때문에 string(C++)으로 각각의 내용을 얻어야 하고,
뭐 중간에는 편의를 위하여 char *tempP등을 선언해서 strncmp등을 이용했습니다.
결과적으로 문자열은 얻었지만... 너무 막 코딩의 느낌을 지울 수가 없어서

위와 같은 상황이라면 고수님들은 어떤식으로 구조를 잡을지 궁금합니다.

저는 대략
먼저 string.find함수로 내용을 test,test2,sublen,substr 크게 네덩이로 나눠서 각각 string 변수에 다시 집어넣고
sublen의 내용을 다시 파싱하기 위하여 sub_len만큼 |로루프를 돌리면서 다시 안의 내용을 $를 이용해서 잘라냈습니다.
이때 첫번째 포문에서 find로 얻어온 position이 구분자가 |이기 때문에 ^|, 또한 find함수에 의하여 잡히기 때문에
일단 find에 의해서 찾아진 값의 검사를 위하여 find함수로 잡아낸 포지션을 strncmp(tempP+포지션-2, "^|", 2) == 0로
검사해서 실제 |(구분자)인지 확인 합니다.

이때, 문제가 sub str의 데이터가 ^^| 이렇게 들어있었다면(실제로 ^가 데이터이고 |가 구분자인 상황)
^|로 strncmp라고 해버리면 문제가 되기 때문에 ^|로 걸리면 다시
strncmp로 앞의 3자리 비교를 합니다.(^^|인지 아닌지)
(char *를 사용한 이유는 c++은 완전 초보인데다 string함수를 처음 써보는 관계로 string함수도 c처럼 직접
char *형 변수+숫자 하여 직접 해당 번지의 내용을 읽어 낼 수 없었기 때문입니다 ㅠ _ㅠ)

위와같이 매우 구차한 방법으로 검사를 하고 있는 상황 입니다.
실제로 포문이 저거말고 ^까지 파싱을위해 하나더 있는상황에서 코드를 보면 스스로 짜놓고도 챙피 합니다.

뭔가 string에 준비된 멋진 함수가 많을 것 같기도 하고 이렇게 구차하게 구현하는것 말고
좀더 아름-_-다운 방법이 있을 것이다라는 생각에 질문을 올려 봅니다.

슈더코드로 제안해주셔도 좋고 직접 내용을 작성해주셔도 좋습니다.

공부하는 입장에서 하나하나 할때마다 뭔가 더 좋은 방법이 있을텐데 라는 생각때문에 하루하루가 매우 힘든 초보 였습니다.

좋은 하루 보내시길 바랍니다.

geneven의 이미지

저는 이번학기 컴파일러를 배우면서 문자열에서 토큰 추출하는것에 감동 먹었습니다. 그전까찌는 토큰은 무조건 공백으로 결정하거나 했었는데..
lex를 한번 배워보세요

sabihanl의 이미지

lex라 일단 검색부터 해봐야겠네요 ^^
일단 이번 문제는 C/C++을 이용해야 하는 상황이라
lex가 뭔지부터 검색해봐야겠네요
감사합니다 ^ _^ //

klyx의 이미지

boost의 정규표현식 라이브러리를 이용해보면 어떨까요?
다만, boost의 정규표현식의 경우 컴파일해서 써야되고 배포시에 라이브러리도 같이 들어가야되므로 배보다 배꼽이 클지도 모르겠는데,
저런식으로 파싱을 자주해야한다면 유용할수 도 있다고 생각합니다.
(참고로 전 boost의 정규표현식라이브러리는 써본적 없습니다-_-;)

sabihanl의 이미지

일단 이번에 할 내용은 일회성 파싱이라
라이브러리까지 이용하기는 좀 그렇고
학습을위하여 꼭 사용해보겠습니다.
요새 코딩에 뭔가 좀 흥미를 느끼고 있어서 유용한 정보 감사합니다 ^^

kaeri17의 이미지

주어진것은 BNF형식으로 나타내면 그닥 복잡할것 같지는 않네요

생각보다 간단한 문법이 될것 같아요.

TC++PL에 4장인가? 계산기 인터프리터 만드는 부분이 있습니다. 그쪽 참고하시면 도움이 되실듯

sabihanl의 이미지

좋은 조언 감사드립니다 ^^
참고 해 보도록 하겠습니다. :)

cinsk의 이미지

sabihanl의 이미지

대신 string의 find를 사용하고 있습니다.
역시 손에익은 strtok가 편하긴한데
string계열 사용하다보니... 엄청 좋네요 : )

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.