1

很抱歉,我的英语很差,很难表达这个问题。所以,我们直接上一个简单的例子。

假设我们有一个主题字符串"apple:banana:cherry:durian"。我们要匹配主语,并分别拥有$1$2$3和、、和。我使用的模式是, 并且会如预期的那样。但是,将代替.$4"apple""banana""cherry""durian"^(\w+)(?::(.*?))*$$1"apple"$2"durian""banana"

因为要匹配的主题字符串不需要是 4 项,例如可以是"one:two:three", and$1$2will be "one"and "three"。同样,缺少中间项目。

在这种情况下使用的正确模式是什么?顺便说一句,我将在 C++ 代码中使用 PCRE2,所以没有splitPerl 内置函数。谢谢。

4

2 回答 2

3

:如果输入包含由, like分隔的严格感兴趣的项目,如item1:item2:item3问题中的尝试所示,那么您可以使用正则表达式模式

[^:]+

它匹配不是 的连续字符:,因此是第一个的子字符串:。这可能也需要捕获([^:]+),取决于整体方法。如何使用它来获得所有这些匹配取决于语言。†</sup>

在 C++ 中有不同的方法来解决这个问题。使用std::regex_iterator

#include <string>
#include <vector>
#include <iterator>
#include <regex>
#include <iostream>

int main()
{
    std::string str{R"(one:two:three)"};
    std::regex r{R"([^:]+)"};

    std::vector<std::string> result{};

    auto it = std::sregex_iterator(str.begin(), str.end(), r);
    auto end = std::sregex_iterator();
    for(; it != end; ++it) {
        auto match = *it;
        result.push_back(match[0].str());
    }

    std::cout << "Input string: " << str << '\n';
    for(auto i : result)
        std::cout << i << '\n';
}

按预期打印。

也可以使用std::regex_search,即使它在第一次匹配时返回——通过迭代字符串以在每次匹配后移动搜索开始

#include <string>
#include <regex>
#include <iostream>

int main()
{
    std::string str{"one:two:three"};
    std::regex r{"[^:]+"};

    std::smatch res;

    std::string::const_iterator search_beg( str.cbegin() );
    while ( regex_search( search_beg, str.cend(), res, r ) )
    {
        std::cout << res[0] << '\n';  
        search_beg = res.suffix().first;
    }
    std::cout << '\n';
}

(有了这个字符串和正则表达式,我们不需要原始字符串文字,所以我在这里删除了它们。)


†</sup>这个问题最初被标记为perl(没有c ++),也在文本中明确提到它(仍然存在),这个答案的原始版本引用了Perl

/([^:]+)/g

/g修饰符”用于“全局”以查找所有匹配项。是//模式分隔符。

当此表达式绑定 ( =~ ) 到具有目标字符串的变量时,整个表达式在预期列表的上下文中使用时返回匹配列表,因此可以直接将其分配给数组变量。

my @captures = $string =~ /[^:]+/g;

(当按字面意思使用时,()不需要捕获)

分配给一个数组提供了这个“列表上下文”。如果在“标量上下文”中使用匹配,其中需要单个值,例如在if测试条件中或分配给标量变量,则返回单个真/假(通常是1or '',空字符串) .

于 2021-10-20T17:39:12.973 回答
2

重复一个捕获组只会捕获最后一次迭代的值。相反,您可以使用\G锚点来获得连续匹配。

如果整个字符串只能包含用冒号分隔的单词字符:

(?:^(?=\w+(?::\w+)+$)|\G(?!^):)\K\w+

模式匹配:

  • (?:非捕获组
    • ^断言字符串的开始
    • (?=\w+(?::\w+)+$)从当前位置断言 1+ 个单词字符和 1+ 个重复:和 1+ 个单词字符直到字符串的末尾
    • |或者
    • \G(?!^):在上一场比赛结束时断言位置,而不是在开始和比赛中:
  • )关闭非捕获组
  • \K\w+忘记到目前为止匹配的内容,并匹配1+单词字符

正则表达式演示

要从字符串的开头也只允许单词,并在单词 chars 之后允许其他字符:

\G:?\K\w+

正则表达式演示

于 2021-10-20T17:51:18.393 回答