0

I have the following string:

std::string ob = R"({ "U" : 972448093270,"u" : 972448098626,"pu" : 972448093117,"b" : [["54019.38","0.414"],["54016.91","0.002"],["54016.80","0.180"],["54016.51","0.001"],["54012.74","0.001"],["54012.38","0.001"],["54011.65","0.044"],["54011.57","0.005"],["54011.40","0.001"],["54011.27","0.200"],["54011.26","0.200"],["54011.25","0.784"],["54011.12","0.200"],["54011.11","0.312"],["54011.04","1.920"],["54010.67","0.123"],["54010.39","0.025"],["54008.59","0.074"],["54008.58","0.167"],["54008.06","0.010"]]})";

Starting from "b" I want all the numbers split and joined in a vector, so effectively I want my vector to look like this:

54019.38  0.414  54016.91  etc

I have implemented the followint with C++20 ranges/views

#include <iostream>
#include <vector>
#include <ranges>

auto to_vector(auto&& rng) 
{
    std::vector<std::ranges::range_value_t<decltype(rng)>> v;
    if constexpr (std::ranges::sized_range<decltype(rng)>) {
        v.reserve(std::ranges::size(rng));
    }
    std::ranges::copy(rng, std::back_inserter(v));
    return v;
}

int main() 
{
    
    std::string ob = R"({ "U" : 972448093270,"u" : 972448098626,"pu" : 972448093117,"b" : [["54019.38","0.414"],["54016.91","0.002"],["54016.80","0.180"],["54016.51","0.001"],["54012.74","0.001"],["54012.38","0.001"],["54011.65","0.044"],["54011.57","0.005"],["54011.40","0.001"],["54011.27","0.200"],["54011.26","0.200"],["54011.25","0.784"],["54011.12","0.200"],["54011.11","0.312"],["54011.04","1.920"],["54010.67","0.123"],["54010.39","0.025"],["54008.59","0.074"],["54008.58","0.167"],["54008.06","0.010"]]})";
    auto digits = ob | std::views::drop_while([](auto i) {return i != 'b'; }) | std::views::split('"') | std::views::join;
    auto vec = to_vector(digits);

    for (auto const& item : vec) {
        std::cout << item <<" ";
    }
}

Unfortunately instead of expected output I got

`b   :   [ [ 5 4 0 1 9 . 3 8 , 0 . 4 1 4 ] , [ 5 4 0 1 6 . 9 1 , 0 . 0 0 2 ] , [ 5 4 0 1 6 . 8 0 , 0 . 1 8 0 ] , [ 5 4 0 1 6 . 5 1 , 0 . 0 0 1 ] , [ 5 4 0 1 2 . 7 4 , 0 . 0 0 1 ] , [ 5 4 0 1 2 . 3 8 , 0 . 0 0 1 ] , [ 5 4 0 1 1 . 6 5 , 0 . 0 4 4 ] ...etc

So I have each character in a vector individually instead of splitting whatever was between "'s
Can someone please help me fix this, thanks in advance.

Eduard Rostomyan
  • 7,050
  • 2
  • 37
  • 76
  • Might be easier to use `jq` => `jq -r '.b[][]'` – Martin York Jan 31 '22 at 22:42
  • @MartinYork can you please be more specific, I didn't follow – Eduard Rostomyan Jan 31 '22 at 22:51
  • jq is a command line tool for filtering and processing JSON. – Martin York Jan 31 '22 at 23:03
  • 1
    jq is a command line tool for filtering and processing JSON. Have you seen all those jokes around the internet. `I can do this with regular expressions`. Sure you can make a hack and do this with views. But it will not be robust and likely to break in the long run (you should only be doing this as a quick hack if you want to test something). But if you are doing it as a quick hack to test something, you may as well use a good specialized tool that already does 99% of what you do. – Martin York Jan 31 '22 at 23:51
  • I don't understand what you're trying to do, but you probably want to use an actual json parser. `split(c) | join` basically just filters out all the characters equal to `c`. If you actually want the numbers, flattened, there's a lot more work to do. It would also help if the question made clear what it was you actually wanted ... like is `vec` supposed to be a `vector`? I dunno. – Barry Feb 01 '22 at 08:45
  • 2
    If you find yourself writing `decltype(arg)` when you do `auto&& arg`, then you've already lost the benefit of abbreviated function templates, so don't do it. Even more when you find yourself writing `decltype(arg)` twice. Just `template auto to_vector(R&& rng)` – Barry Feb 01 '22 at 08:48

0 Answers0