3

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?

2 Answers2

3

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);
  }
}

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.

dfrib
  • 70,367
  • 12
  • 127
  • 192
  • With the help of the Boost.Hof library and a lambda that lifts the `xor` operator, one can easily get to write `auto views = plate_code | chunk_by(eitherButNotBoth(is_digit));`, like [this](https://godbolt.org/z/dKnPM3c6W). – Enlico Aug 09 '23 at 13:34
  • @Jarod42 Thanks! Enlico: I'll keep my answer without the Boost.Hof's lift, but feel free to add that variation as a separate answer. – dfrib Aug 09 '23 at 14:08
  • 1
    @Enlico: we don't want `xor` though but `==` :-) – Jarod42 Aug 09 '23 at 14:37
  • @Jarod42, thanks. In which case the lambda is not needed as we have `std::equal_to{}`. Thanks, I've posted is an answer. – Enlico Aug 09 '23 at 15:18
1

Just thought of sharing a way to make the already proposed solution a bit (imho) neater, closer to spoken English, only by using existing abstractions, specifically boost::hana::on from Boost.Hana and BOOST_HOF_LIFT from Boost.Hof, together with some using.

The buisness-logic line is just

auto views = plate_code | chunk_by(equal ^on^ is_digit);

It sounds a bit like: "chunk by equality applied on the whether each is_digit".

But equal is just a synonym for std::equal_to{},

constexpr auto equal = std::equal_to{};

and is_digit is an object wrapping std::isdigit by means of Boost.Hof,

constexpr auto is_digit = BOOST_HOF_LIFT(std::isdigit);

so no further logic was written by me, I've just reused existing building blocks.

Complete example here.

Enlico
  • 23,259
  • 6
  • 48
  • 102
  • Interesting but a bit strange solution with ^-^) thank you – Daniil Rozanov Aug 09 '23 at 15:26
  • [Louis Dionne](https://github.com/ldionne), author of Boost.Hana, most likely took inspiration from Haskell for the name of this combinator. In Haskell, you'd write ``(==) `on` isDigit`` (even though, Haskell's [`on`](https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Function.html#v:on) is a bit less general than Boost.Hana's). – Enlico Aug 09 '23 at 15:43