2016-08-04 8 views
1

理想の行動に各区切り文字を入れる:'#'トークン化文字列、およびそれ自身のトークン

  • すべてが# =コメント)を無視しています。
  • 空の行はトークンを作成しません。
  • '{'はBLOCK_OPENのトークンを作成します。
  • '}'はタイプBLOCK_CLOSEのトークンを作成します。
  • '='は、タイプEQUALSのトークンを作成します。
  • 他のすべては、タイプLABELのトークンを作成します。
  • トークンは空のスペース(S)ほとんどの入力の場合

、完璧に私のトークン化機能を持っていてはいけません。

show_position = {X = -9 Y = 78}

注スペースの欠如一個のバグを除いて!

返されるベクトルに"x""-9"の間に"="がありません。

どうすればこのバグを修正できますか?私はデバッグしようとしましたが、何がうまくいかないのか分かりませんでした。新鮮な眼のペアは恩恵です。


これは私がトークン化する方法である:

std::vector<Token> tokenizeLine(const std::string str) 
{ 
    std::vector<Token> tokens; 

    std::string::size_type start = 0; 
    std::string::size_type end = 0; 
    while (end != std::string::npos) 
    { 
     enum POSES 
     { 
      EQUALS, 
      OPEN, 
      CLOSE, 
      SPACE, 
      EOL, 
      RETURN, 
      TAB, 
      COMMENT, 
      POSES_SIZE 
     }; 
     std::string::size_type pos[] = 
     { 
      str.find('=', start), 
      str.find('{', start), 
      str.find('}', start), 
      str.find(' ', start), 
      str.find('\n', start), 
      str.find('\r', start), 
      str.find('\t', start), 
      str.find('#', start) 
     }; 
     end = *std::min_element(pos, &pos[POSES_SIZE]); 

     switch (str[start]) 
     { 
     case('=') : 
      tokens.push_back(Token(Token::EQUALS, "=")); 
      break; 
     case('{') : 
      tokens.push_back(Token(Token::BLOCK_OPEN, "{")); 
      break; 
     case('}') : 
      tokens.push_back(Token(Token::BLOCK_CLOSE, "}")); 
      break; 
     case(' ') : 
     case('\n') : 
     case('\r') : 
     case('\t'): 
      break; 
     case('#') : 
      return tokens; 
      break; 
     default: 
      if(str.substr(start, end - start).length() > 0) 
       tokens.push_back(Token(Token::LABEL, str.substr(start, end - start))); 
     } 

     // If at end, use start=maxSize. Else use start=end+delimiter. 
     start = ((end > (std::string::npos - sizeof(char))) 
      ? std::string::npos : end + sizeof(char)); 
    } 

    return tokens; 
} 

は、ここでは、あなたの家の快適さで実行することができるものです。

std::vector<std::string> tokenizeLine(const std::string str) 
{ 
    std::vector<std::string> tokens; 

    std::string::size_type start = 0; 
    std::string::size_type end = 0; 
    while (end != std::string::npos) 
    { 
     enum POSES // Deliminators 
     { 
      EQUALS, 
      OPEN, 
      CLOSE, 
      SPACE, 
      EOL, 
      RETURN, 
      TAB, 
      COMMENT, 
      POSES_SIZE 
     }; 
     std::string::size_type pos[] = 
     { 
      str.find('=', start), 
      str.find('{', start), 
      str.find('}', start), 
      str.find(' ', start), 
      str.find('\n', start), 
      str.find('\r', start), 
      str.find('\t', start), 
      str.find('#', start) 
     }; 
     end = *std::min_element(pos, &pos[POSES_SIZE]); 

     switch (str[start]) 
     { 
     case('=') : 
      tokens.push_back("="); 
      break; 
     case('{') : 
      tokens.push_back("{"); 
      break; 
     case('}') : 
      tokens.push_back("}"); 
      break; 
     case(' ') : 
     case('\n') : 
     case('\r') : 
     case('\t'): 
      break; 
     case('#') : 
      return tokens; 
      break; 
     default: 
      if(str.substr(start, end - start).length() > 0) 
       tokens.push_back(str.substr(start, end - start)); 
     } 

     // If at end, use start=maxSize. Else use start=end+delimiter. 
     start = ((end > (std::string::npos - sizeof(char))) 
      ? std::string::npos : end + sizeof(char)); 
    } 
    return tokens; 
} 
+2

@NathanOliver与えられたコードが意図したとおりに機能しないため、コードレビューで話題にならないでしょう。 – syb0rg

+0

申し訳ありませんが明確ではありません。問題を明らかにするために質問を編集しました。 –

+1

@IvanRubinson 2番目のコードは正常に動作します:http://ideone.com/i1tRr8 MCVEを提供してください。 – alexeykuzmin0

答えて

1

これはregex_iteratorの仕事のように聞こえます!あなたが扱おうとしているような文脈自由な言語では、正規表現を打つのは難しいです。だから、あなたのコードを形に変えようとするのではなく、それを投げ捨てて、その仕事に適切なツールを使用してください。

この正規表現は、あなたの希望のトークンのそれぞれについて、個別のキャプチャを持っている:あなたは、単にそれを解析できconst auto input = "#Comment\n\nshow_position = { x=-9 y =78 }"s、のような入力が与えられ

\s*(?:\n|(#[^\n]*)|(\{)|(\})|(=)|([^{}= \t\r\n]+)) 

Live Example

として:

vector<Tokens> tokens; 

for_each(sregex_iterator(cbegin(input), cend(input), re), sregex_iterator(), [&](const auto& i) { 
    if (i[1].length() > 0U) { 
     tokens.emplace_back(Token::COMMENT, i[1]); 
    } else if (i[2].length() > 0U) { 
     tokens.emplace_back(Token::BLOCK_OPEN, "{"s); 
    } else if (i[3].length() > 0U) { 
     tokens.emplace_back(Token::BLOCK_CLOSE, "}"s); 
    } else if (i[4].length() > 0U) { 
     tokens.emplace_back(Token::EQUALS, "="s); 
    } else if (i[5].length() > 0U) { 
     tokens.emplace_back(Token::LABEL, i[5]); 
    } 
}); 

Live Example

-1

TL; DR:これを修正するには、追加することがswitchIdeOnedefault支店の--endからifへの声明。

ここで問題となるのは、見つかったトークンのタイプがLABELである場合、1つのシンボルを必要以上に飲み込むということです。だからの直後のシンボルは、xの後に無視されます。それらの間に空白を追加すると、この空白は無視され、=の符号が正しく解析されます。

LABELトークンの直後の記号は、次の理由により飲み込まれます。文字#endを無視します。他のすべてのタイプのトークンについては、endはトークンの最後の文字を表しますが、LABELのトークンタイプの場合はendがトークンの後の最初の文字の数に等しいので、これは完全にうまくいきます。

+0

入力にコメントはありませんか? –

+0

あなたのコメントは、おそらく 'LABEL'です。文字列を表現するために使用し、 'switch'の' default'ブランチで処理される 'Token'の型。 – alexeykuzmin0

+0

これは 'str [start]'を範囲外にします(end&start underflows)。 –

関連する問題