3

数学表記順列をその要素に分割するコードが必要です。この順列を想定してみましょう。

順列

順列文字列は次のようになります。

「(1,2,5)(3,4)」または「(3,4)(1,2,5)」または「(3,4)(5,1,2)」

私が試したパターンは次のとおりです。

  • ([0-9]+[ ]*,[ ]*)*[0-9]+順列サイクルごとに。"(1,2,5)(3,4)"これにより、文字列が と の 2 つの文字列に"1,2,5"分割されます"3,4"
  • ([0-9]+)サイクル内の各要素に対して。これにより、各サイクルが個々の数に分割されます。

このページでこのパターンを試したところ、うまく機能しました。また、私はそれらを C++11 正規表現ライブラリで使用して、良い結果を得ました:

#include <iostream>
#include <string>

#include <regex>

void elements(const std::string &input)
{
    const std::regex ElementRegEx("[0-9]+");

    for (std::sregex_iterator Element(input.begin(), input.end(), ElementRegEx); Element != std::sregex_iterator(); ++Element)
    {
        const std::string CurrentElement(*Element->begin());
        std::cout << '\t' << CurrentElement << '\n';
    }
}

void cycles(const std::string &input)
{
    const std::regex CycleRegEx("([0-9]+[ ]*,[ ]*)*[0-9]+");

    for (std::sregex_iterator Cycle(input.begin(), input.end(), CycleRegEx); Cycle != std::sregex_iterator(); ++Cycle)
    {
        const std::string CurrentCycle(*Cycle->begin());
        std::cout << CurrentCycle << '\n';

        elements(CurrentCycle);
    }
}

int main(int argc, char **argv)
{
    std::string input("(1,2,5)(3,4)");

    std::cout << "input: " << input << "\n\n";

    cycles(input);
    return 0;
}

Visual Studio 2010 (10.0) でコンパイルした出力:

input: (1,2,5)(3,4)

1,2,5
    1
    2
    5
3,4
    3
    4

残念ながら、私のプロジェクトでは C++11 ツールを使用できません。プロジェクトは Linux プラットフォームで実行され、gcc 4.2.3 でコンパイルする必要があります。そのため、ヘッダーで C 正規表現ライブラリを使用する必要があります。regex.hしたがって、同じパターンを使用してもライブラリが異なると、異なる結果が得られます。

テストコードは次のとおりです

void elements(const std::string &input)
{
    regex_t ElementRegEx;
    regcomp(&ElementRegEx, "([0-9]+)", REG_EXTENDED);

    regmatch_t ElementMatches[MAX_MATCHES];
    if (!regexec(&ElementRegEx, input.c_str(), MAX_MATCHES, ElementMatches, 0))
    {
        int Element = 0;

        while ((ElementMatches[Element].rm_so != -1) && (ElementMatches[Element].rm_eo != -1))
        {
            regmatch_t &ElementMatch = ElementMatches[Element];
            std::stringstream CurrentElement(input.substr(ElementMatch.rm_so, ElementMatch.rm_eo - ElementMatch.rm_so));
            std::cout << '\t' << CurrentElement << '\n';

            ++Element;
        }
    }

    regfree(&ElementRegEx);
}

void cycles(const std::string &input)
{
    regex_t CycleRegEx;
    regcomp(&CycleRegEx, "([0-9]+[ ]*,[ ]*)*[0-9]+", REG_EXTENDED);

    regmatch_t CycleMatches[MAX_MATCHES];
    if (!regexec(&CycleRegEx, input.c_str(), MAX_MATCHES, CycleMatches, 0))
    {
        int Cycle = 0;

        while ((CycleMatches[Cycle].rm_so != -1) && (CycleMatches[Cycle].rm_eo != -1))
        {
            regmatch_t &CycleMatch = CycleMatches[Cycle];
            const std::string CurrentCycle(input.substr(CycleMatch.rm_so, CycleMatch.rm_eo - CycleMatch.rm_so));
            std::cout << CurrentCycle << '\n';

            elements(CurrentCycle);
            ++Cycle;
        }
    }

    regfree(&CycleRegEx);
}

int main(int argc, char **argv)
{
    cycles("(1,2,5)(3,4)")
    return 0;
}

予想される出力は C++11 正規表現を使用した場合と同じですが、実際の出力は次のとおりです。

input: (1,2,5)(3,4)

1,2,5
    1
    1
2,
    2
    2

最後に、質問は次のとおりです。

  • C正規表現エンジンを誤解している場所について誰かがヒントをくれますか?
  • C 正規表現と C++ 正規表現で動作が異なるのはなぜですか?
4

1 に答える 1

2

の出力を誤解していますregexecpmatchバッファ(後)は、文字列内の連続した一致ではなく、正規表現のサブ一致で満たさpmatch[0]ます。

たとえば、正規表現がと[a-z]([+ ])([0-9])一致する場合x+5、は(一致全体)をpmatch[0]参照し、はとをそれぞれ参照します。x+5pmatch[1]pmatch[2]+5

regexec前の試合の終わりから始めて、ループでを繰り返す必要があります:

int start = 0;
while (!regexec(&ElementRegEx, input.c_str() + start, MAX_MATCHES, ElementMatches, 0))
{
    regmatch_t &ElementMatch = ElementMatches[0];
    std::string CurrentElement(input.substr(start + ElementMatch.rm_so, ElementMatch.rm_eo - ElementMatch.rm_so));
    std::cout << '\t' << CurrentElement << '\n';
    start += ElementMatch.rm_eo;
}
于 2012-10-31T10:11:52.620 に答える