c++algorithmrange-v3

how to split a string into sequences defined by a rule with range v3 library?


I have a string of vehicle number, for example kz083y68 and i want to convert it into kz 083 y 68 with spaces. String also could be 3486nv09, etc, so there is no fixed position to split. All i need is to split subsequences of numbers and letters by spaces.

Obviously this can be done manually, but I'm wondering if there is a function in the range-v3 library for this. In general, maybe there is a function that takes some predicate (isdigit, iseven, isdog) and splits given range to corresponding subrange?


Solution

  • Using views::chunk_by to get a set of sub-views:

    #include <cctype>
    #include <fmt/ranges.h>
    #include <ranges>
    #include <string>
    
    int main() {
      std::string_view plate_code{"kz083y68"};
      auto views = plate_code |
                std::views::chunk_by([](auto lhs, auto rhs) {
                  // Thanks @Jarod42 for the simplified predicate!
                  return std::isdigit(lhs) == std::isdigit(rhs);
                });
      for (auto const view : views) {
        fmt::print("{}", view);
      }  // ['k', 'z']['0', '8', '3']['y']['6', '8']
    }
    

    DEMO.

    You can use views::join_with to get a single view with a selected delimiter:

    int main() {
      std::string_view plate_code{"kz083y68"};
      auto view = plate_code | std::views::chunk_by([](auto lhs, auto rhs) {
                    return std::isdigit(lhs) == std::isdigit(rhs);
                  }) |
                  std::views::join_with(' ');
      fmt::print("{}", view);
      // ['k', 'z', ' ', '0', '8', '3', ' ', 'y', ' ', '6', '8']
    }
    

    DEMO.