Ranges und String Split
-
Hi,
eigentlich eine typische Aufgabe: einen String an einem bestimmten Zeichen splitten.
Ich habe das mal genutzt um ein bisschen mitstd::rangeszu spielen und kann mir das Verhalten nicht erklären.Ich splitte ein String an dem Zeichen "/".
split3- einfach durchiterieren und ausgeben funktioniert wie man das erwarten würde.
sry, war dumm - Iterator wird inkrementiert und sosplit1- dreht die Reihenfolge, kann mir jemand erklären warum?
split2- findet den Trenner nicht und gibt daher als erste Position den ganzen String aus. Ich verstehe, dass ein String eine Range aufcharist und man daher einencharbraucht, hätte aber erwartet, dass das dann ein Fehler gibt, da die Typen nicht zusammen passen.#include <ranges> #include <iostream> constexpr void split1(const std::string& key) { auto parts = std::views::split(key,'/'); if (parts.empty()) std::cout << "empty"; auto first = parts.begin(); const auto second = first++; if (second == std::end(parts)) std::cout << std::ranges::to<std::string>(*first) << " \n"; std::cout << std::ranges::to<std::string>(*first) << " " <<std::ranges::to<std::string>(*second) << " \n"; } constexpr void split2(const std::string& key) { auto parts = std::views::split(key,"/"); if (parts.empty()) std::cout << "empty"; auto first = parts.begin(); const auto second = first++; if (second == std::end(parts)) std::cout << std::ranges::to<std::string>(*first) << " \n"; std::cout << std::ranges::to<std::string>(*first) << " " <<std::ranges::to<std::string>(*second) << " \n"; } constexpr void split3(const std::string& key) { for(auto part : std::views::split(key, '/')) std::cout << std::string_view(part) << " "; } int main() { std::string key("test/bla"); split1(key); split2(key); split3(key); }Link zum direkt rumspielen: https://godbolt.org/z/sqW58czas
-
Benutze in
split2using std::operator""sv; auto parts = std::views::split(key,"/"sv);wie auch im Beispiel zu std::ranges::views::split verwendet wird.
Die Erklärung steht unter "Notes":
The delimiter pattern generally should not be an ordinary string literal, as it will consider the null terminator to be necessary part of the delimiter; therefore, it is advisable to use a
std::string_viewliteral instead.
-
@Th69 Ok, verstehe ich.
Aber das ist doch Kontraintuitiv. Man versucht mit allen Mitteln C++ einfacher und weniger Fehleranfällig zu machen und dann macht man sowas.
-
@Schlangenmensch sagte in Ranges und String Split:
@Th69 Ok, verstehe ich.
Aber das ist doch Kontraintuitiv. Man versucht mit allen Mitteln C++ einfacher und weniger Fehleranfällig zu machen und dann macht man sowas.
Vielleicht wollte man erlauben, an '\0' zu splitten, was ja sonst nicht möglich wäre.
-
@wob sagte in Ranges und String Split:
Vielleicht wollte man erlauben, an '\0' zu splitten, was ja sonst nicht möglich wäre.
Wieso nicht? Gerade mit string_view-Literalen wäre es ein leichtes, '\0' im Delimiter zu haben - und sogar an beliebiger Stelle.
Ich vermute eher, dass man konsistent bleiben möchte zu all den modernen Sprachmitteln, und kein Sondersüppchen für C-Stringliterale wollte, dass bei denen und nur bei denen das letzte Zeichen nicht gilt. Das ist ziemlich unschön, aber zumindest kommt dann von der modernen C++-Seite her nur eine Regel, die konsistent angewendet wird. Die Sonderungen der C-Stringliterale kommen halt aus der Geschichte. Leider ist damit die einfache und intuitive Art ein Stringliteral zu schreiben mit historischen Sonderregeln verseucht, aber die Syntax von C-Stringliteralen und Stringviewliteralen zu vertauschen hat man sich dann (zurecht!) doch nicht getraut.
-
@SeppJ sagte in Ranges und String Split:
Wieso nicht? Gerade mit string_view-Literalen wäre es ein leichtes, '\0' im Delimiter zu haben - und sogar an beliebiger Stelle.
Jetzt verwirrst du mich. Ist das nicht genau das, was ich geschrieben habe?
Das wieso nicht: weil man in C-Strings kein \0 als Zeichen haben kann. Wie soll ich mit einem C-String sagen, dass ich den String
{ 'h', 'a', 'l', 'l', 'o', 'x', '0x00', 'x', 'S', 'e', 'p', 'p', 'J' }and "x\0x" splitten will - geht halt nicht, weil das dasselbe wie "x" wäre (also nach C-String-Regeln, jetzt nicht pointer vs array)