boost::regexで数値範囲判定

[戻る]
keichan [E-Mail] 2006/07/05(水) 15:59:00
お世話になります。
keichanです。

現在テキストボックスから取得した文字列を正規表現でマッチングを行っています。
そこで、指定した範囲以外の数値が入力されている場合はマッチしないようにしたいと考えてい
ます。

例えば、
"string,30"とテキストボックスに入力されている場合、且つ数値の指定範囲が10〜20であった
場合にマッチしない。としたいのです。

boost::regex("\\s*\\w+\\s*[,]\\s*/*ここをどのように記述すれば良いのでしょうか?
*/");

これが出来なければ
boost::regex("\\s*\\w+\\s*[,]\\s*\\d+");
でマッチングを行ってから数値文字列のみを抜き出して数値変換し、
範囲判定を行わなければいけないので、マッチングのみで解決する方法を探しております。

よろしくお願い致します。

開発環境:
WinXP Pro
VC2005
boost 1.33.1

よすむら 2006/07/05(水) 17:16:15
keichan様

>数値の指定範囲が10〜20であった場合にマッチしない

を考えれば

,([0-9])$|([3-9][0-9])$ではいかがでしょうか。

よすむら 2006/07/05(水) 18:12:31
,([0-9])$|([2][1-9])$|([3-9][0-9])$|([1-9]+[0-9][0-9])$でした。

keichan [E-Mail] 2006/07/05(水) 18:29:02
よすむら様、ご回答ありがとうございます。

>,([0-9])$|([3-9][0-9])$ではいかがでしょうか。
こちらの方で試すと10〜20がマッチしない。という結果になりました。
ですので、例題では((1[0-9])|20)で解決しそうです。

しかしながら、実際には指定範囲が負の整数や、実数値も入ってきます。
ご提示頂いた方法ですと、すべてのパターンを網羅するのにかなり骨が折れそうな感じがしま
す。
>これが出来なければ
>boost::regex("\\s*\\w+\\s*[,]\\s*\\d+");
>でマッチングを行ってから数値文字列のみを抜き出して数値変換し、
>範囲判定を行わなければいけないので、マッチングのみで解決する方法を探しております。
こっちの方が早く作れそうなので。。。


理想としましては、汎用的な値域マッチングができて且つできるだけスマートな方法を模索して
いるのですが・・・
厳しそうですか?

整数型・実数型の区別は別パラメータで持たせていますので、
汎用的な整数用のマッチングパターン・実数用のマッチングパターンの提案をご提示いただけれ
ば幸いです。
(アルゴリズムな感じの話題に摩り替わってるような・・・)

keichan [E-Mail] 2006/07/07(金) 17:10:09
[[解決]]
>,([0-9])$|([2][1-9])$|([3-9][0-9])$|([1-9]+[0-9][0-9])$でした。
今気づきましたが、
([0-9])$|([2][1-9])$|([3-9][0-9])$|([1-9][0-9]+[0-9])$
ではないですか?^^;


スマートな方法を考案するのが難しそうですので、一度力技で作成してみようかと思います。

一応解決ということで。。。

keichan [E-Mail] 2006/07/07(金) 18:42:28
正の整数で一定の数値以上しか受け付けないバージョンだけ力技でちょっと作ってみました。
ここはこうした方がいいよ。とか汚いソースで読めんwとか。ご意見を頂ければ幸いです。

仕様:
 数値範囲指定は{}で囲む
   {1,100}  // 1以上100以下の値を受け付ける
   {1,}     // 1以上の値を受け付ける
   {,1}     // 1以下の値を受け付ける
 直値指定は生の数値を記述する
   10       // 10のみ受け付ける
 |で複数指定可能
   0|{100,} // 0か100以上の値を受け付ける



↓ここからソースコード
-------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <string>
#include <boost/regex.hpp>
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>

inline void delete_separator(std::string& in_string)
{
    std::string buf;
    for( unsigned int i=0; i<in_string.length(); ++i )
    {
        if( in_string[i] != ' ' && in_string[i] != '\t' && in_string
[i] != '\r' && in_string[i] != '\n' )
            buf += in_string[i];
    }
    in_string = buf;
}

template<typename T>
inline T get_min_num(const std::string& in_string)
{
    std::string min_num_string;
    size_t min_begin_pos = in_string.find("{")+1;
    const size_t min_end_pos = in_string.find(",");
    do {
        min_num_string += in_string[min_begin_pos++];
    } while( min_begin_pos != min_end_pos );

    T buf;
    try {
        buf = boost::lexical_cast<T>(min_num_string);
    } catch( boost::bad_lexical_cast& ) {
        /// エラーメッセージの表示
        std::string error(in_string);
        error = "書式入力が間違っています。["+ error + "]";
        std::cout << error << std::endl;
        return 0;
    }
    return buf;
}

inline int get_figure(int in_figure)
{
    int figure = 0;
    do {
        ++figure;
        in_figure /= 10;
    } while( in_figure );
    return figure;
}

keichan [E-Mail] 2006/07/07(金) 18:43:16
enum REGEX_SYNTAX_FLAG {
    ONLY_MIN,
    ONLY_MAX,
    BOTH_MINMAX,
};
std::string get_regex_syntax(const int in_min, const int in_max, 
REGEX_SYNTAX_FLAG in_flg)
{
    std::string syntax("(");
    switch( in_flg ) {
    case ONLY_MIN:    /// 最小値しか入っていない。つまり in_min<=n の構文を書
く
        {
            if( in_min >= 0 ) {
                /// 桁数を取得
                const int figure = get_figure(in_min);
                /// 桁数以上は無条件に入力可能
                syntax += "([1-9][0-9]{" + 
boost::lexical_cast<std::string>(figure) + ",})";
                /// 同桁数に入りま〜す
                std::vector<int>    figure_num;    /// 各
桁の数値を入れておく箱
                for( int i=figure-1; i >= 0; --i ) {
                    figure_num.push_back
(static_cast<int>((in_min/pow(10, static_cast<float>(i))))%10);
                }
                for( size_t i=0; i<figure_num.size(); 
++i ) {
                    std::string same_figure("(");
                    for( size_t j=0; j<i; ++j ) {
                        same_figure += "[" + 
boost::lexical_cast<std::string>(figure_num[j]) + "]";
                    }
                    same_figure += "[" + 
boost::lexical_cast<std::string>(figure_num[i] + (i==figure_num.size()-1 ? 0 : 
1)) + (i!=0 ? "-9]" : "]");
                    if( i != figure_num.size()-1 )
                        same_figure += "[0-9]{" 
+ boost::lexical_cast<std::string>(figure_num.size()-i-1) + "}";
                    same_figure += ")";
                    syntax += "|" + same_figure;
                }
            }
        }
        break;
    }
    syntax += (")");
    return syntax;
}

bool check_integer(std::string& out_format, std::string in_format)
{
    if( in_format.empty() )
        return true;

    /// |演算子があると、複数指定の証
    boost::char_separator<char> or_token("|");
    boost::tokenizer<boost::char_separator<char> >    tokens
(in_format, or_token);
    typedef boost::tokenizer<boost::char_separator<char> >::iterator 
token_iterator;

    out_format += "(";
    for( token_iterator token_it = tokens.begin(); token_it!=tokens.end
(); ++token_it ) {
        std::string token_string = *token_it;
        delete_separator(token_string);
        if( token_string.find("{") == std::string::npos ) {
            // 直値指定
            out_format += token_string;
        } else {
            // 範囲指定
            size_t colon_pos = token_string.find(",");
            bool min = ('0' <= token_string[colon_pos-1] && 
token_string[colon_pos-1] <= '9');
            if( min ) {    /* {1,}の形式*/
                int min_num = get_min_num<int>
(token_string);
                out_format += get_regex_syntax(min_num, 0, 
REGEX_SYNTAX_FLAG::ONLY_MIN);
            } else {            /* 上記以外の形式。ありえ
ないので入力エラー*/
                /// エラーメッセージの表示
                std::string error(*token_it);
                error = "書式入力が間違っています。["+ error 
+ "]";
                std::cout << error << std::endl;
                return false;
            }
        }
        token_iterator last_check_it = token_it;
        if( ++last_check_it != tokens.end() )
            out_format += "|";
    }
    out_format += ")";
    return true;
}

int main()
{
    std::string regex_string;
    std::string format("0|{105,}");
    check_integer(regex_string, format);

    std::cout << regex_string << std::endl;
    boost::regex re(regex_string);
    while(1) {
        std::string in;
        std::cin >> in;
        if( boost::regex_match(in, re) ) {
            std::cout << "found" << std::endl;
        } else {
            std::cout << "not found" << std::endl;
        }
    }
    return 0;
}
-------------------------------------------------------------------------------
↑ここまで

投稿最大文字数をオーバーしましたので分割しましたm(_ _)m

古いスレッドには追加発言できません。