使用字符串分隔符(标准 C )在 C 中解析(拆分)字符串

新手上路,请多包涵

我正在使用以下内容在 C++ 中解析一个字符串:

 using namespace std;

string parsed,input="text to be parsed";
stringstream input_stringstream(input);

if (getline(input_stringstream,parsed,' '))
{
     // do some processing.
}

使用单个字符定界符进行解析很好。但是,如果我想使用字符串作为分隔符怎么办。

示例:我想拆分:

 scott>=tiger

>= 作为分隔符,这样我就可以得到斯科特和老虎。

原文由 TheCrazyProgrammer 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 942
2 个回答

您可以使用 std::string::find() 函数查找字符串分隔符的位置,然后使用 std::string::substr() 获取令牌。

例子:

 std::string s = "scott>=tiger";
std::string delimiter = ">=";
std::string token = s.substr(0, s.find(delimiter)); // token is "scott"

  • find(const string& str, size_t pos = 0) 函数返回 str 在字符串中第一次出现的位置,或者 npos 如果没有找到字符串。

  • substr(size_t pos = 0, size_t n = npos) 函数返回对象的子字符串,从位置 pos 开始,长度为 npos


如果您有多个分隔符,则在提取一个标记后,您可以将其删除(包括分隔符)以继续进行后续提取(如果要保留原始字符串,只需使用 s = s.substr(pos + delimiter.length()); ):

 s.erase(0, s.find(delimiter) + delimiter.length());

这样您就可以轻松地循环获取每个令牌。

完整示例

std::string s = "scott>=tiger>=mushroom";
std::string delimiter = ">=";

size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << token << std::endl;
    s.erase(0, pos + delimiter.length());
}
std::cout << s << std::endl;

输出:

 scott
tiger
mushroom

原文由 Vincenzo Pii 发布,翻译遵循 CC BY-SA 3.0 许可协议

我查看了答案,并没有看到可以输入范围循环的基于迭代器的方法,所以我做了一个。

这使用 C++17 string_views,所以它不应该分配字符串的副本。

 struct StringSplit
{
    struct Iterator
    {
        size_t tokenStart_ = 0;
        size_t tokenEnd_ = 0;
        std::string str_;
        std::string_view view_;
        std::string delimiter_;
        bool done_ = false;

        Iterator()
        {
            // End iterator.
            done_ = true;
        }

        Iterator(std::string str, std::string delimiter)
            : str_{std::move(str)}, view_{str_}, delimiter_{
                                                     std::move(delimiter)}
        {
            tokenEnd_ = view_.find(delimiter_, tokenStart_);
        }

        std::string_view operator*()
        {
            return view_.substr(tokenStart_, tokenEnd_ - tokenStart_);
        }

        Iterator &operator++()
        {
            if (tokenEnd_ == std::string::npos)
            {
                done_ = true;
                return *this;
            }

            tokenStart_ = tokenEnd_ + delimiter_.size();
            tokenEnd_ = view_.find(delimiter_, tokenStart_);
            return *this;
        }

        bool operator!=(Iterator &other)
        {
            // We only check if both points to the end.
            if (done_ && other.done_)
            {
                return false;
            }

            return true;
        }
    };

    Iterator beginIter_;

    StringSplit(std::string str, std::string delim)
        : beginIter_{std::move(str), std::move(delim)}
    {
    }

    Iterator begin()
    {
        return beginIter_;
    }

    Iterator end()
    {
        return Iterator{};
    }
};

示例用法是:

 int main()
{
    for (auto token : StringSplit{"<>foo<>bar<><>bar<><>baz<><>", "<>"})
    {
        std::cout << "TOKEN: '" << token << "'" << std::endl;
    }
}

哪个打印:

 TOKEN: ''
TOKEN: 'foo'
TOKEN: 'bar'
TOKEN: ''
TOKEN: 'bar'
TOKEN: ''
TOKEN: 'baz'
TOKEN: ''
TOKEN: ''

它正确处理字符串开头和结尾的空条目。

原文由 Calmarius 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题