簡體   English   中英

將 std::string 標記為結構

[英]Tokenize a std::string to a struct

假設我有以下要根據分隔符“>”標記化的字符串:

std::string veg = "orange>kiwi>apple>potato";

我希望字符串中的每個項目都放置在具有以下格式的結構中:

struct pack_item
{
    std::string it1;
    std::string it2;
    std::string it3;
    std::string it4;
};

我知道如何這樣做:

pack_item pitem;

std::stringstream veg_ss(veg);
std::string veg_item;

std::getline(veg_ss, veg_item, '>')
pitem.it1 = veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it2 = veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it3 = veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it4 = veg_item;

有沒有更好的單線方式來做到這一點?

像這樣:

#include <string>
#include <vector>
#include <sstream>
#include <iostream>

std::string veg = "orange>kiwi>apple>potato";

typedef std::vector<std::string> it_vec;

int main(int argc, char* argv[]) {
    it_vec vec;
    
    std::stringstream veg_ss(veg);
    std::string veg_item;

    while (std::getline(veg_ss, veg_item, '>')) {
        vec.push_back(veg_item);
    }
    
    for (const std::string& vec_item : vec) {
        std::cout << vec_item << std::endl;
    }
}

正如評論中所建議的,您可以這樣使用 for 循環:

pack_item a;
std::array<std::reference_wrapper<std::string>, 4> arr{a.it1, a.it2, a.it3, a.it4};

constexpr std::string_view veg = "orange>kiwi>apple>potato";
std::istringstream ss(veg.data());

std::string str;

for(std::size_t idx = 0; std::getline(ss, str, '>'); ++idx){
    arr[idx].get() = std::move(str);
}

如果你的意思是真正意義上的“單線”,那么你可能會很討厭並使用:

std::getline(std::getline(std::getline(std::getline(ss, a.it1, '>'), a.it2, '>'), a.it3, '>'), a.it4, '>');

您不需要中間變量。

pack_item pitem;

std::stringstream veg_ss(veg);

std::getline(veg_ss, pitem.it1, '>');
std::getline(veg_ss, pitem.it2, '>');
std::getline(veg_ss, pitem.it3, '>');
std::getline(veg_ss, pitem.it4, '>');

您可能希望將其設為 function,例如operator >> (具有類似的operator <<

std::istream& operator >>(std::istream& is, pack_item & pitem) {
    std::getline(is, pitem.it1, '>');
    std::getline(is, pitem.it2, '>');
    std::getline(is, pitem.it3, '>');
    std::getline(is, pitem.it4, '>');
    return is;
}

std::ostream& operator <<(std::ostream& os, pack_item & pitem) {
    return os << pitem.it1 << '>'
              << pitem.it2 << '>'
              << pitem.it3 << '>'
              << pitem.it4 << '>';
}

int main() {
    std::stringstream veg_ss("orange>kiwi>apple>potato>");
    pack_item pitem;
    veg_ss >> pitem;
}

有沒有更好的單線方式來做到這一點?

您可以創建一個類型,它的>>讀取一個字符串直到一個定界符,並在一個語句中讀取所有四個元素。 那真的“更好”了嗎?

template <bool is_const>
struct delimited_string;

template<>
struct delimited_string<true> {
    const std::string & string;
    char delim;
};

template<>
struct delimited_string<false> {
    std::string & string;
    char delim;
};

delimited_string(const std::string &, char) -> delimited_string<true>;
delimited_string(std::string &, char) -> delimited_string<false>;

std::istream& operator >>(std::istream& is, delimited_string<false> s) {
    return std::getline(is, s.string, s.delim);
}

template <bool is_const>
std::ostream& operator <<(std::ostream& os, delimited_string<is_const> s) {
    return os << s.string << s.delim;
}

std::istream& operator >>(std::istream& is, pack_item & pitem) {
    return is >> delimited_string { pitem.it1, '>' }
              >> delimited_string { pitem.it2, '>' }
              >> delimited_string { pitem.it3, '>' }
              >> delimited_string { pitem.it4, '>' };
}

std::ostream& operator <<(std::ostream& os, const pack_item & pitem) {
    return os << delimited_string { pitem.it1, '>' }
              << delimited_string { pitem.it2, '>' }
              << delimited_string { pitem.it3, '>' }
              << delimited_string { pitem.it4, '>' };
}

的確:

#include <iostream>
#include <sstream>
#include <string>

struct pack_item
{
    std::string it1;
    std::string it2;
    std::string it3;
    std::string it4;
};

pack_item pack( const std::string & s )
{
  pack_item p;
  getline(getline(getline(getline(std::istringstream(s), p.it1,'>'), p.it2,'>'), p.it3,'>'), p.it4);
  return p;
}

int main()
{
  auto pitem = pack( "orange>kiwi>apple>potato" );
  
  std::cout << pitem.it4 << "<" << pitem.it3 << "<" << pitem.it2 << "<" << pitem.it1 << "\n";
}

順便說一句,多行代碼沒有錯。 追求單線往往會分散注意力,無法以正確的方式做事™。

我要做的是創建一個以 std::string_view 作為參數的構造函數(第二個是預定義的,將是分隔符),並使用查找 function。

使用 std::string_view 的原因發布在這里: How exactly is std::string_view faster than const std::string&?

struct pack_item
{
    std::string it1;
    std::string it2;
    std::string it3;
    std::string it4;

    pack_item():it1(){}

    pack_item(std::string_view in, char sep = '>'){
        
        auto ptr = in.begin();
        auto l_ptr = ptr;
        ptr = std::find(ptr, in.end(), sep);
        it1 = std::string(l_ptr, ptr++);
        l_ptr = ptr;
        ptr = std::find(ptr, in.end(), sep);
        it2 = std::string(l_ptr, ptr++);
        l_ptr = ptr;
        ptr = std::find(ptr, in.end(), sep);
        it3 = std::string(l_ptr, ptr++);
        l_ptr = ptr;
        ptr = std::find(ptr, in.end(), sep);
        it4 = std::string(l_ptr, ptr++);
        
        
    }

};

你可以在這里看到,如果你願意,這可以很容易地轉換成一個循環,並通過檢查來停止它:

if(ptr == in.end()) break;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM