8

私はブーストの正規表現ライブラリを使用していますが、名前付きの一致が見つかったかどうかを判断し、その情報を使用するのは少し面倒です。名前付き一致を検出するには、次のようにします。

typedef boost::match_result<string::const_iterator> matches_t;
typedef matches_t::const_reference match_t;
boost::regex re("(?:(?<type1>aaaa)|(?<type2>bbbb)" /*...*/ "|(?<typeN>abcdefg)");
string str(SOME_STRING);
matches_t what;
boost::match_flag_type flags = boost::match_default;

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  if((match_t type1 = what["type1"]).matched)
  {
     // do stuff with type1
  }
  else if((match_t type2 = what["type2"]).matched)
  {
     // do stuff with type2
  }
  // ...
  else if((match_t typeN = what["typeN"]).matched)
  {
     // do stuff with typeN
  }
}

それがうまくいくなら、それは素晴らしいことです。スコーピングは if の本体に制限され、メモリを効率的に使用でき、かなりきれいに見えます。残念ながら、リスト内で変数を定義できないため、機能しません。:(

これは可能性がありました:

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  match_t found = what["type1"];
  if(found.matched)
  {
     // do stuff with type1
  }
  else if((found = what["type2"]).matched)
  {
     // do stuff with type2
  }
  // ...
  else if((found = what["typeN"]).matched)
  {
     // do stuff with typeN
  }
}

ただし、match_t は const 参照であるため、代入できません。 (tl;dr また、基になる型が何であるかはわかりません。通常、正規表現のこの 1 つの例以外で使用できる、より一般的なソリューションを好むので、知りたくありません。 std:: move() was used around what[...] it gets even more verbose and the documentation does that it uses move semantics for sub_match. もちろん、このすべてはこの最初の文で与えられた理由により意味がありませんパラグラフ)

別のオプションはこれです:

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  match_t type1 = what["type1"];
  if(type1.matched)
  {
     // do stuff with type1
  }
  else {
    match_t type2 = what["type2"];
    if(type2.matched)
    {
       // do stuff with type2
    }
    // ...
          else {
            match_t typeN = what["typeN"];
            if((match_t typeN = what["typeN"]).matched)
            {
               // do stuff with typeN
            }
          }
    // ...
    }
  }
}

ブレースのネストが深いため、これは好きではありません。

おそらく、次のようbreakに各ifボディの最後に s を使用してループ構造を悪用します。

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  do{
    {
      match_t type1 = what["type1"];
      if(type1.matched)
      {
         // do stuff with type1
         break;
      }
    }
    {
      match_t type2 = what["type2"];
      if(type2.matched)
      {
         // do stuff with type2
         break;
      }
    }
    // ...
    {
      match_t typeN = what["typeN"];
      if(typeN.matched)
      {
         // do stuff with typeN
         break;
      }
    }
  } while(0);
}

どちらが優れていますが、それでも素晴らしいとは言えません。マクロを使用すると、ノイズの多くを視界から隠すことができます。お気に入り:

#define IF(declare, cond) do{{declare;if(cond){                
#define ELSE_IF(declare, cond) break;}}{declare; if(cond){     
#define ELSE break;}}{{                                        
#define END_IF break;}}}while(0);                              

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  IF(match_t type1 = what["type1"], type1.matched)
  {
     // do stuff with type1
  }
  ELSE_IF(match_t type2 = what["type2"], type2.matched)
  {
     // do stuff with type2
  }
    // ...
  ELSE_IF(match_t typeN = what["typeN"], typeN.matched)
  {
     // do stuff with typeN
  }
  END_IF
}

中括弧は実際にはマクロによって暗示されていますが、それらを言い換えると読みやすくなります。

私が考えることができるもう1つのオプションは、boost::sub_match クラスに移動し、その型を戻り値がメンバーの戻り値になる bool に変換する変換関数を追加することですmatched。次に、if 式で match_t 変数を宣言すると、if によって自動的にブール値に変換されます。私がまだそこにいるかどうかはわかりませんが、それは一般的ではありません。

スタイル的に、私が提案するものは良いか悪いかです (実際に機能するのは最後の 3 つだけなので、コメントはおそらくそれらに限定します)。

また、誰かより良い提案はありますか?それらが優れていると思う理由を述べてください。

4

3 に答える 3

3

このようなことを行うことができます (このコードはコンパイラに対してテストされていないことに注意してください)

// create a map between match types and actions
std::map<std::string, std::function<match_t>> actions;
actions["type1"] = [&](match_t type) {...};

// iterate through the actions map and check each match type
for(auto kvp : actions)
{
   match_t type = what[kvp.first];
   if(type.matched)
   {
      // do stuff with this result
      kvp.second(type);
   }
}
于 2013-05-24T05:30:00.690 に答える
0

match_tのオーバーロードでラップを書くことができますoperator bool:

struct bmatch
{
    matches_t::const_reference ref;
    bmatch(matches_t::const_reference r)
    :ref(r)
    {}

    operator bool() const
    {
        return ref.matched;
    }
};

その後:

if (bmatch type1 = what["type1"])
{ //Use type2.ref
}
else if (bmatch type2 = what["type2"])
{ //Use type2.ref
}

追加のポイントについては、オーバーロードすることもできますoperator->:

    matches_t::const_reference operator->() const
    {
        return ref;
    }
于 2013-05-24T15:09:36.923 に答える