0

私は準 SCPI コマンド パーサーに取り組んでおり、引用符で囲まれた文字列を無視して、コロンに基づいて文字列を分割したいと考えています。コロンの間にテキストがない場合、空の文字列を取得したい。

この正規表現を EditPad Pro 7.2.2 で使用すると、まさに私の望みどおりに動作します。(([^:\"']|\"[^\"] \"|'[^'] ')+)?

例として、次のデータ文字列を使用します: :foo:::bar:baz

[empty],foo,[empty],[empty],bar,baz の 6 件のヒットがあります。

ここまでは順調ですね。ただし、私のコードでは、std::tr1::regex を使用して、同じデータ文字列で9 つのヒットを取得しています。空でないヒットごとに余分な空のヒットが発生しているようです

void RICommandState::InitRawCommandEnum(const std::string& full_command)
{
    // Split string by colons, but ignore text within quotes.
    static const std::tr1::regex split_by_colon("(([^:\"']|\"[^\"]*\"|'[^']*')+)?");

    raw_command_list.clear();
    raw_command_index = 0;

    DebugPrintf(ZONE_REMOTE, (TEXT("InitRawCommandEnum FULL '%S'"), full_command.c_str()));

    const std::tr1::sregex_token_iterator end;
    for (std::tr1::sregex_token_iterator it(full_command.begin(),
                                            full_command.end(),
                                            split_by_colon);
         it != end;
         it++)
    {
        raw_command_list.push_back(*it);
        const std::string temp(*it);
        DebugPrintf(ZONE_REMOTE, (TEXT("InitRawCommandEnum '%S'"), temp.c_str()));
    }

    DebugPrintf(ZONE_REMOTE, (TEXT("InitRawCommandEnum hits = %d"), raw_command_list.size()));
}

そして、ここに私の出力があります:

InitRawCommandEnum FULL ':foo:::bar:baz'
InitRawCommandEnum ''
InitRawCommandEnum 'foo'
InitRawCommandEnum ''
InitRawCommandEnum ''
InitRawCommandEnum ''
InitRawCommandEnum 'bar'
InitRawCommandEnum ''
InitRawCommandEnum 'baz'
InitRawCommandEnum ''
InitRawCommandEnum hits = 9

最も重要な問題は、正規表現検索で、コロンで区切られたトークンごとに 1 つ (そして 1 つだけ) ヒットするようにするにはどうすればよいかということです。検索式に問題がありますか?

それとも、結果を誤解していますか?空でない文字列の後の空の文字列には特別な意味がありますか? もしそうなら、何?その場合、単純に無視するのが正しい解決策ですか?

余談ですが、なぜ私のコードが EditPad Pro とは異なる動作をするのか非常に興味があります。EditPad は、正規表現を試すのに便利なテスト環境です。

ありがとう!

4

1 に答える 1

1

空の文字列の意味はまだ明確ではありませんが、無視することで回避できました。検索文字列内のヒットの位置を追跡し、文字列内でより遠くにある結果のみを処理します。

ここに変更なしの私のコードがあります。私の正規表現検索式は少し異なることに注意してください。ただし、それは答えにとって重要ではありません。

void RICommandState::InitRawCommandEnum(const std::string& full_command)
{
    // Split string by colons, but ignore text within quotes.
    static const std::tr1::regex split_by_colon("(?:[^:\"']|\"[^\"]*\"|'[^']*')*");

    raw_command_list.clear();
    raw_command_index = 0;

    std::tr1::sregex_iterator::difference_type minPosition = 0;
    const std::tr1::sregex_iterator end;
    for (std::tr1::sregex_iterator it(full_command.begin(),
                                      full_command.end(),
                                      split_by_colon);
         it != end;
         it++)
    {
        if (it->position() >= minPosition)
        {
            raw_command_list.push_back(it->str());
            minPosition = it->position() + it->length() + 1;
        }
    }
}
于 2013-09-04T22:18:19.580 に答える