【问题标题】:How To Extract Tokens from String?如何从字符串中提取标记?
【发布时间】:2020-11-26 19:09:15
【问题描述】:

编辑:有人可以添加正则表达式解决方案吗?我正在查看以下正则表达式:

[\(\)!*-+^]

我有一个函数,它根据我在正文中声明的特殊字符从文本中提取标记。

函数存在2个问题:

1) 不打印特殊字符。

2)两个特殊字符相邻时输出错误

所以我做了一个改变,解决了问题 1(正如我从一些测试的结果中看到的那样) 但是没有修复数字 2,有什么帮助吗?

注意:我使用的是 C++11 标准,不打算使用 boost

示例: 给定:a+(b*c) 我期待:a,+,(,b,*,c,)

给定:a+b 我期待:a,+,b

给定:ab+ 我期待:ab,+

鉴于:a b+ 我期待:a b,+

【问题讨论】:

  • 您能否展示一些示例输入和您的预期输出?
  • 这是因为你在执行last_pos = pos + 1时跳过了特殊字符。你可以找出特殊字符str[pos]
  • @CoryKramer 更新:我添加了一些边缘案例,请刷新
  • @armagedescu 如果我不做 last_pos=pos+1 代码将不间断地运行
  • @CoryKramer 有什么帮助吗?

标签: c++ regex string split


【解决方案1】:

这是一个应该解析你想要的标记的正则表达式解决方案:

void find(std::string str)
{
    static const std::regex r(R"(\+|\^|-|\*|!|\(|\)|([\w|\s]+))");
    std::copy( std::sregex_token_iterator(str.begin(), str.end(), r, 0),
               std::sregex_token_iterator(),
               std::ostream_iterator<std::string>(std::cout, "\n"));
}

这是demo。

这是explanation。

请注意,如果您想进行通用解析,这不是一个好主意。正则表达式很快就会变得笨拙(如果还没有的话),并且有更好的工具可以为您做到这一点。

【讨论】:

  • 谢谢,但它会打印两个额外的空行
  • 一个在顶部,一个在末尾​​span>
  • 对,我忘了转义^。固定。
  • 谢谢,一件小事,如果我不想打印它们而是将它们保存到现有向量中怎么办?
  • 最后一个参数类似于std::back_inserter(v),其中v 是vector&lt;string&gt;
【解决方案2】:

您没有很好地处理空字符串。在处理空字符串之前,请检查以确保它不为空。

#include <sstream>
#include <string>
#include <vector>
#include <cassert>

using std::string;
using std::stringstream;
using std::vector;

namespace {

// Parse a string into a vector of tokens by special characters.
auto find(string str) -> vector<string> {
    auto result = vector<string>{};
    auto pos = string::size_type{};
    auto last_pos = string::size_type{};

    while ((pos = str.find_first_of("+^-*!()", last_pos)) != string::npos) {
        // Is there a token before the special character?
        if (pos - last_pos > 0) {
            result.push_back(str.substr(last_pos, pos - last_pos));
        }

        last_pos = pos + 1;

        // Add the special character as a token.
        result.push_back(str.substr(pos, 1));
    }

    auto last = str.substr(last_pos);

    // Is there a trailing token after the last found special character?    
    if (!last.empty()) {
        result.push_back(str.substr(last_pos));
    }

    return result;
}

// Helper routine.
// Join a vector of strings together using a given separator.
auto join(vector<string> const& v, string sep) -> string {
    auto ss = stringstream{};
    auto first = true;

    for (auto const& s : v) {
        if (first) {
            ss << s;
            first = false;
        } else {
            ss << sep << s;
        }
    }

    return ss.str();
}

// Helper routine.
// Returns a string representing the tokenized string.
auto check(string s) -> string {
    auto v = find(s);
    auto result = join(v, ",");
    return result;
}

} // anon

int main() {
    // Unit tests to check that the string parses and tokenizes into the expected string.
    assert(check("a+(b*c)") == "a,+,(,b,*,c,)");
    assert(check("a+b") == "a,+,b");
    assert(check("ab+") == "ab,+");
    assert(check("a b+") == "a b,+");
    assert(check("a") == "a");
    assert(check("aa") == "aa");
    assert(check("+") == "+");
    assert(check("++") == "+,+");
    assert(check("a+") == "a,+");
    assert(check("+a") == "+,a");
    assert(check("") == "");
}

【讨论】:

  • 在代码中频繁添加 cmets 比显示一堆代码对访问者更好。
  • 谢谢,如果有使用正则表达式的解决方案,有人可以指出
  • 请将该请求也添加到问题中。
  • @daniel • 正则表达式不是一个好的通用解析器。如果您需要通用解析器,请考虑Spirit Parser Framework,它可以通过提供语法来进行通用解析。
  • @cigien 编辑了问题并添加了可能的正则表达式
猜你喜欢
  • 2021-05-22
  • 1970-01-01
  • 2020-11-28
  • 2019-12-08
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
相关资源
最近更新 更多